Implementando eSIM

A tecnologia de SIM incorporado (eSIM ou eUICC) permite que usuários móveis baixem um perfil de operadora e ativem o serviço de uma operadora sem ter um cartão SIM físico. É uma especificação global orientada pela GSMA que permite o provisionamento remoto de SIM (RSP) de qualquer dispositivo móvel. A partir do Android 9, a estrutura do Android fornece APIs padrão para acessar o eSIM e gerenciar perfis de assinatura no eSIM. Essas APIs eUICC permitem que terceiros desenvolvam seus próprios aplicativos de operadora e assistentes de perfil local (LPAs) em dispositivos Android habilitados para eSIM.

O LPA é um aplicativo de sistema autônomo que deve ser incluído na imagem de compilação do Android. O gerenciamento dos perfis no eSIM geralmente é feito pelo LPA, pois serve como uma ponte entre o SM-DP+ (serviço remoto que prepara, armazena e entrega pacotes de perfis aos dispositivos) e o chip eUICC. O LPA APK pode incluir opcionalmente um componente de interface do usuário, chamado de LPA UI ou LUI, para fornecer um local central para o usuário final gerenciar todos os perfis de assinatura incorporados. A estrutura do Android descobre e se conecta automaticamente ao melhor LPA disponível e roteia todas as operações eUICC por meio de uma instância de LPA.

Arquitetura simplificada de provisionamento remoto de SIM (RSP)

Figura 1. Arquitetura RSP simplificada

As operadoras de rede móvel interessadas em criar um aplicativo de operadora devem consultar as APIs no EuiccManager , que fornece operações de gerenciamento de perfil de alto nível, como downloadSubscription() , switchToSubscription() e deleteSubscription() .

Se você for um OEM de dispositivo interessado em criar seu próprio aplicativo do sistema LPA, deverá estender o EuiccService para a estrutura do Android para se conectar aos seus serviços LPA. Além disso, você deve usar as APIs em EuiccCardManager , que fornecem funções ES10x baseadas em GSMA RSP v2.0. Essas funções são usadas para emitir comandos para o chip eUICC, como prepareDownload() , loadBoundProfilePackage() , retrieveNotificationList() e resetMemory() .

As APIs no EuiccManager requerem um aplicativo LPA implementado corretamente para funcionar e o chamador das APIs EuiccCardManager deve ser um LPA. Isso é imposto pela estrutura do Android.

Dispositivos com Android 10 ou superior podem ser compatíveis com dispositivos com vários eSIMs. Para obter mais informações, consulte Suporte a vários eSIMs .

Fazendo um aplicativo de operadora

As APIs eUICC no Android 9 possibilitam que as operadoras de rede móvel criem aplicativos com a marca da operadora para gerenciar seus perfis diretamente. Isso inclui baixar e excluir perfis de assinatura de propriedade da operadora, bem como alternar para um perfil de propriedade de uma operadora.

EuiccManager

EuiccManager é o principal ponto de entrada para os aplicativos interagirem com o LPA. Isso inclui aplicativos de operadora que baixam, excluem e mudam para assinaturas de propriedade da operadora. Isso também inclui o aplicativo do sistema LUI, que fornece um local/UI central para gerenciar todas as assinaturas incorporadas e pode ser um aplicativo separado daquele que fornece o EuiccService .

Para usar as APIs públicas, um aplicativo de operadora deve primeiro obter a instância de EuiccManager por meio de Context#getSystemService :

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

Você deve verificar se o eSIM é compatível com o dispositivo antes de realizar qualquer operação de eSIM. EuiccManager#isEnabled() geralmente retorna true se o recurso android.hardware.telephony.euicc estiver definido e um pacote LPA estiver presente.

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

Para obter informações sobre o hardware eUICC e a versão do eSIM OS:

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

Muitas APIs, como downloadSubscription() e switchToSubscription() , usam retornos de chamada PendingIntent , pois podem levar segundos ou até minutos para serem concluídos. PendingIntent é enviado com um código de resultado no espaço EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_ , que fornece códigos de erro definidos pela estrutura, bem como um código de resultado detalhado arbitrário propagado do LPA como EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE , permitindo que o aplicativo da operadora rastreie para fins de registro/depuração. O retorno de chamada PendingIntent deve ser BroadcastReceiver .

Para baixar uma determinada assinatura para download (criada a partir de um código de ativação ou código 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*/);
                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);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent,
        PendingIntent.FLAG_UPDATE_CURRENT);
mgr.downloadSubscription(sub, true /* switchAfterDownload */,
        callbackIntent);

Para mudar para uma assinatura com base no ID da assinatura:

// 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);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent,
        PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);

Para obter uma lista completa de APIs EuiccManager e exemplos de código, consulte APIs eUICC .

Erros solucionáveis

Há alguns casos em que o sistema não consegue concluir a operação do eSIM, mas o erro pode ser resolvido pelo usuário. Por exemplo, downloadSubscription pode falhar se os metadados do perfil indicarem que é necessário um código de confirmação da operadora . Ou switchToSubscription pode falhar se o aplicativo da operadora tiver privilégios de operadora sobre o perfil de destino (ou seja, a operadora possuir o perfil), mas não tiver privilégios de operadora sobre o perfil habilitado no momento e, portanto, o consentimento do usuário é necessário.

Para esses casos, o retorno de chamada do chamador é chamado com EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR . O Intent de retorno de chamada contém extras internos de tal forma que quando o chamador o passa para EuiccManager#startResolutionActivity , a resolução pode ser solicitada por meio da LUI. Usando o código de confirmação por exemplo novamente, EuiccManager#startResolutionActivity aciona uma tela LUI que permite ao usuário inserir um código de confirmação; após a inserção do código, a operação de download é retomada. Essa abordagem fornece ao aplicativo da operadora controle total sobre quando a interface do usuário é exibida, mas oferece ao LPA/LUI um método extensível para adicionar um novo tratamento de problemas recuperáveis ​​pelo usuário no futuro, sem a necessidade de alterações nos aplicativos cliente.

O Android 9 define esses erros solucionáveis ​​em EuiccService , que a LUI deve manipular:

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

Privilégios da operadora

Se você for uma operadora desenvolvendo seu próprio aplicativo de operadora que chama o EuiccManager para baixar perfis em um dispositivo, seu perfil deve incluir regras de privilégio de operadora correspondentes ao seu aplicativo de operadora nos metadados. Isso ocorre porque perfis de assinatura pertencentes a diferentes operadoras podem coexistir no eUICC de um dispositivo, e cada aplicativo de operadora deve ter permissão para acessar apenas os perfis pertencentes a essa operadora. Por exemplo, a operadora A não deve poder baixar, ativar ou desativar um perfil de propriedade da operadora B.

Para garantir que um perfil seja acessível apenas ao seu proprietário, o Android usa um mecanismo para conceder privilégios especiais ao aplicativo do proprietário do perfil (ou seja, o aplicativo da operadora). A plataforma Android carrega os certificados armazenados no arquivo de regras de acesso (ARF) do perfil e concede permissão aos aplicativos assinados por esses certificados para fazer chamadas às APIs do EuiccManager . O processo de alto nível é descrito abaixo:

  1. Operadora assina o APK do aplicativo da operadora; a ferramenta apksigner anexa o certificado de chave pública ao APK.
  2. O Operator/SM-DP+ prepara um perfil e seus metadados, que incluem um ARF que contém:

    1. Assinatura (SHA-1 ou SHA-256) do certificado de chave pública do aplicativo da operadora (obrigatório)
    2. Nome do pacote do aplicativo da operadora (opcional)
  3. O aplicativo da operadora tenta realizar uma operação eUICC por meio da API EuiccManager .

  4. A plataforma Android verifica que o hash SHA-1 ou SHA-256 do certificado do aplicativo chamador corresponde à assinatura do certificado obtido do ARF do perfil de destino. Se o nome do pacote do aplicativo da operadora estiver incluído no ARF, ele também deverá corresponder ao nome do pacote do aplicativo chamador.

  5. Depois que a assinatura e o nome do pacote (se incluído) são verificados, o privilégio da operadora é concedido ao aplicativo chamador sobre o perfil de destino.

Como os metadados do perfil podem estar disponíveis fora do próprio perfil (para que o LPA possa recuperar os metadados do perfil do SM-DP+ antes que o perfil seja baixado ou do ISD-R quando o perfil estiver desabilitado), ele deve conter as mesmas regras de privilégio de operadora como no perfil.

O eUICC OS e o SM-DP+ devem suportar uma marca proprietária BF76 nos metadados do perfil. O conteúdo da tag deve ser as mesmas regras de privilégio de operadora retornadas pelo applet de regra de acesso (ARA) definido em Privilégios de operadora 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
    }
}

Para obter mais detalhes sobre a assinatura de aplicativos, consulte Assinar seu aplicativo . Para obter detalhes sobre privilégios de operadora, consulte Privilégios de operadora UICC .

Fazendo um aplicativo LPA

Você pode implementar seu próprio LPA, que deve ser conectado às APIs do Android Euicc. As seções a seguir fornecem uma breve visão geral de como criar um aplicativo LPA e integrá-lo ao sistema Android.

Requisitos de hardware/modem

O LPA e o eSIM OS no chip eUICC devem suportar pelo menos GSMA RSP (Remote SIM Provisioning) v2.0 ou v2.2. Você também deve planejar o uso de servidores SM-DP+ e SM-DS que tenham uma versão RSP correspondente. Para arquitetura RSP detalhada, consulte Especificação de arquitetura RSP GSMA SGP.21 .

Além disso, para integrar com as APIs eUICC no Android 9, o modem do dispositivo deve enviar recursos de terminal com suporte para recursos eUICC codificados (gerenciamento de perfil local e download de perfil). Ele também precisa implementar os seguintes métodos:

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

  • IRadioConfig HAL v1.0: getSimSlotsStatus

O modem deve reconhecer o eSIM com o perfil de inicialização padrão ativado como um SIM válido e manter o SIM ligado.

Para dispositivos que executam o Android 10, uma matriz de ID de slot eUICC não removível deve ser definida. Por exemplo, consulte 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>

Para obter uma lista completa de requisitos de modem, consulte Requisitos de modem para suporte a eSIM .

EuiccService

Um LPA consiste em dois componentes separados (ambos podem ser implementados no mesmo APK): o back-end do LPA e a interface do usuário do LPA ou LUI.

Para implementar o back-end do LPA, você deve estender o EuiccService e declarar esse serviço em seu arquivo de manifesto. O serviço deve exigir a permissão do sistema android.permission.BIND_EUICC_SERVICE para garantir que apenas o sistema possa se vincular a ele. O serviço também deve incluir um filtro de intent com a ação android.service.euicc.EuiccService . A prioridade do filtro de intent deve ser definida como um valor diferente de zero caso várias implementações estejam presentes no dispositivo. Por exemplo:

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

Internamente, a estrutura do Android determina o LPA ativo e interage com ele conforme necessário para oferecer suporte às APIs eUICC do Android. PackageManager é consultado para todos os aplicativos com a permissão android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS , que especifica um serviço para a ação android.service.euicc.EuiccService . O serviço com a prioridade mais alta é selecionado. Se nenhum serviço for encontrado, o suporte a LPA será desabilitado.

Para implementar a LUI, você deve fornecer uma atividade para as seguintes ações:

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

Assim como no serviço, cada atividade deve exigir a permissão do sistema android.permission.BIND_EUICC_SERVICE . Cada um deve ter um filtro de intent com a ação apropriada, a categoria android.service.euicc.category.EUICC_UI e uma prioridade diferente de zero. Lógica semelhante é usada para escolher as implementações para essas atividades como para escolher a implementação de EuiccService . Por exemplo:

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

Isso implica que a interface do usuário que implementa essas telas pode vir de um APK diferente daquele que implementa o EuiccService . Ter um único APK ou vários APKs (por exemplo, um que implementa EuiccService e outro que fornece atividades de LUI) é uma escolha de design.

Gerente de Cartão Euicc

EuiccCardManager é a interface para comunicação com o chip eSIM. Ele fornece funções ES10 (conforme descrito na especificação GSMA RSP) e manipula os comandos de solicitação/resposta APDU de baixo nível, bem como a análise ASN.1. EuiccCardManager é uma API do sistema e pode ser chamada apenas por aplicativos com privilégios do sistema.

Aplicativos de operadora, LPA e APIs Euicc

Figura 2. O aplicativo da operadora e o LPA usam APIs Euicc

As APIs de operação de perfil por meio do EuiccCardManager exigem que o chamador seja um LPA. Isso é imposto pela estrutura do Android. Isso significa que o chamador deve estender EuiccService e ser declarado em seu arquivo de manifesto, conforme descrito nas seções anteriores.

Semelhante ao EuiccManager , para usar as APIs EuiccCardManager , seu LPA deve primeiro obter a instância de EuiccCardManager por meio de Context#getSystemService :

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

Então, para obter todos os perfis no 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);

Internamente, EuiccCardManager se liga ao EuiccCardController (que é executado no processo de telefone) por meio de uma interface AIDL, e cada método EuiccCardManager recebe seu retorno de chamada do processo de telefone por meio de uma interface AIDL dedicada diferente. Ao usar APIs EuiccCardManager , o chamador (LPA) deve fornecer um objeto Executor por meio do qual o retorno de chamada é invocado. Este objeto Executor pode ser executado em um único thread ou em um pool de threads de sua escolha.

A maioria das APIs EuiccCardManager tem o mesmo padrão de uso. Por exemplo, para carregar um pacote de perfil vinculado no eUICC:

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

Para alternar para um perfil diferente com um determinado ICCID:

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

Para obter o endereço SM-DP+ padrão do chip eUICC:

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

Para recuperar uma lista de notificações dos eventos de notificação fornecidos:

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

Ativando um perfil eSIM por meio de um aplicativo de operadora

Em dispositivos com Android 9 ou superior, você pode usar um aplicativo de operadora para ativar o eSIM e baixar perfis. O aplicativo da operadora pode baixar perfis ligando diretamente para downloadSubscription ou fornecendo um código de ativação ao LPA.

Quando um aplicativo de operadora baixa um perfil chamando downloadSubscription , a chamada impõe que o aplicativo possa gerenciar o perfil por meio de uma tag de metadados BF76 que codifica regras de privilégio de operadora para o perfil. Se um perfil não tiver uma tag BF76 ou se sua tag BF76 não corresponder à assinatura do aplicativo da operadora de chamada, o download será rejeitado.

A seção abaixo descreve a ativação de um eSIM por meio de um aplicativo de operadora usando um código de ativação.

Ativando o eSIM usando um código de ativação

Ao usar um código de ativação para ativar um perfil eSIM, o LPA busca um código de ativação do aplicativo da operadora e baixa o perfil. Esse fluxo pode ser iniciado pelo LPA e o LPA pode controlar todo o fluxo da IU, o que significa que nenhuma IU do aplicativo da operadora é mostrada. Essa abordagem ignora a verificação de tags BF76 e as operadoras de rede não precisam implementar todo o fluxo de UI de ativação do eSIM, incluindo o download de um perfil eSIM e o tratamento de erros.

Definindo o serviço de provisionamento eUICC da operadora

O aplicativo LPA e da operadora se comunicam por meio de duas interfaces AIDL : ICarrierEuiccProvisioningService e IGetActivationCodeCallback . O aplicativo da operadora deve implementar uma interface ICarrierEuiccProvisioningService e expô-la em sua declaração de manifesto . O LPA deve se associar a ICarrierEuiccProvisioningService e implementar IGetActivationCodeCallback . Para obter mais informações sobre como implementar e expor uma interface AIDL, consulte Definindo e interface AIDL .

Para definir as interfaces AIDL, crie os seguintes arquivos AIDL para o LPA e os aplicativos da operadora.

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

Exemplo de implementação de LPA

Para vincular à implementação de ICarrierEuiccProvisioningService do aplicativo da operadora, o LPA deve copiar ICarrierEuiccProvisioningService.aidl e IGetActivationCodeCallback.aidl para seu projeto e implementar ServiceConnection .

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

Após a associação à implementação ICarrierEuiccProvisioningService do aplicativo da operadora, o LPA chama getActivationCode ou getActivationCodeForEid para obter o código de ativação do aplicativo da operadora passando a implementação da classe de stub IGetActivationCodeCallback .

A diferença entre getActivationCode e getActivationCodeForEid é que getActivationCodeForEid permite que uma operadora pré-vincule um perfil ao EID do dispositivo antes do início do processo de download.

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

Exemplo de implementação para aplicativo de operadora

Para que o LPA seja vinculado ao aplicativo da operadora, o aplicativo da operadora deve copiar ICarrierEuiccProvisioningService.aidl e IGetActivationCodeCallback.aidl para seu projeto e declarar o serviço ICarrierEuiccProvisioningService no arquivo AndroidManifest.xml . O serviço deve exigir a permissão do sistema android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS para garantir que apenas o LPA, um aplicativo com privilégios do sistema, possa se vincular a ele. O serviço também deve incluir um filtro de intent com a ação 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>

Para implementar o serviço de aplicativo de operadora AIDL, crie um serviço, estenda a classe Stub e implemente os métodos getActivationCode e getActivationCodeForEid . O LPA pode então chamar qualquer um dos métodos para buscar o código de ativação do perfil. O aplicativo da operadora deve responder chamando IGetActivationCodeCallback#onSuccess com o código de ativação se o código foi buscado no servidor da operadora com êxito. Se não tiver êxito, o aplicativo da operadora deverá responder com 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);
            }
      }
}

Iniciando a IU do aplicativo da operadora no fluxo de ativação do LPA

Em dispositivos com Android 11 e superior, o LPA pode iniciar a interface do usuário de um aplicativo de operadora. Isso é útil porque um aplicativo de operadora pode exigir informações adicionais do usuário antes de fornecer um código de ativação ao LPA. Por exemplo, as operadoras podem exigir que os usuários façam login para ativar seus números de telefone ou realizar outros serviços de portabilidade.

Este é o processo para iniciar a IU de um aplicativo de operadora no LPA:

  1. O LPA inicia o fluxo de ativação do aplicativo da operadora enviando o intent android.service.euicc.action.START_CARRIER_ACTIVATION para o pacote do aplicativo da operadora que contém a ação. (O receptor do aplicativo da operadora deve ser protegido na declaração do manifesto com android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" para evitar o recebimento de intents de aplicativos não 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. O aplicativo da operadora faz seu trabalho usando sua própria interface do usuário. Por exemplo, fazer login do usuário ou enviar solicitações HTTP para o back-end da operadora.

  3. O aplicativo da operadora responde ao LPA chamando setResult(int, Intent) e finish() .

    1. Se o aplicativo da operadora responder com RESULT_OK , o LPA continuará o fluxo de ativação. Se o aplicativo da operadora determinar que o usuário deve digitalizar um código QR em vez de permitir que o LPA vincule o serviço do aplicativo da operadora, o aplicativo da operadora responderá ao LPA usando setResult(int, Intent) com RESULT_OK e uma instância Intent contendo o booleano android.telephony.euicc.extra.USE_QR_SCANNER definido como true . O LPA verifica o extra e inicia o scanner QR em vez de vincular a implementação ICarrierEuiccProvisioningService do aplicativo da operadora.
    2. Se o aplicativo da operadora travar ou responder com RESULT_CANCELED (esse é o código de resposta padrão), o LPA cancelará o fluxo de ativação do eSIM.
    3. Se o aplicativo da operadora responder com algo diferente de RESULT_OK ou RESULT_CANCELED , o LPA o tratará como um erro.

    Por motivos de segurança, o LPA não deve aceitar diretamente um código de ativação fornecido na intenção do resultado para garantir que os chamadores não LPA não possam obter um código de ativação do aplicativo da operadora.

Como iniciar o fluxo de ativação do LPA em um aplicativo de operadora

A partir do Android 11, os aplicativos da operadora podem usar APIs eUICC para iniciar uma LUI para ativação do eSIM. Esse método mostra a interface do usuário do fluxo de ativação do eSIM do LPA para ativar o perfil do eSIM. O LPA então envia uma transmissão quando a ativação do perfil eSIM termina.

  1. O LPA deve declarar uma atividade que inclui um filtro de intent com a ação android.service.euicc.action.START_EUICC_ACTIVATION . A prioridade do filtro de intent deve ser definida como um valor diferente de zero caso várias implementações estejam presentes no dispositivo. Por exemplo:

    <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. O aplicativo da operadora faz seu trabalho usando sua própria interface do usuário. Por exemplo, fazer login do usuário ou enviar solicitações HTTP para o back-end da operadora.

  3. Nesse ponto, o aplicativo da operadora deve estar pronto para fornecer um código de ativação por meio de sua implementação ICarrierEuiccProvisioningService . O aplicativo da operadora inicia o LPA chamando startActivityForResult(Intent, int) com a ação android.telephony.euicc.action.START_EUICC_ACTIVATION . O LPA também verifica o booleano extra android.telephony.euicc.extra.USE_QR_SCANNER . Se o valor for true , o LPA iniciará o scanner QR para permitir que o usuário digitalize o código QR do perfil.

  4. No lado do LPA, o LPA se vincula à implementação ICarrierEuiccProvisioningService do aplicativo da operadora para buscar o código de ativação e baixar o perfil correspondente. O LPA exibe todos os elementos de interface do usuário necessários durante o download, como uma tela de carregamento.

  5. Quando o fluxo de ativação do LPA é concluído, o LPA responde ao aplicativo da operadora com um código de resultado, que o aplicativo da operadora processa em onActivityResult(int, int, Intent) .

    1. Se o LPA conseguir baixar o novo perfil eSIM, ele responderá com RESULT_OK .
    2. Se o usuário cancelar a ativação do perfil eSIM no LPA, ele responderá com RESULT_CANCELED .
    3. Se o LPA responder com algo diferente de RESULT_OK ou RESULT_CANCELED , o aplicativo da operadora tratará isso como um erro.

    Por motivos de segurança, o LPA não aceita um código de ativação diretamente no intent fornecido para garantir que os chamadores não LPA não possam obter o código de ativação do aplicativo da operadora.

Suporte a vários eSIMs

Para dispositivos com Android 10 ou superior, a classe EuiccManager é compatível com dispositivos com vários eSIMs. Os dispositivos com um único eSIM que estão atualizando para o Android 10 não exigem nenhuma modificação na implementação do LPA, pois a plataforma associa automaticamente a instância do EuiccManager ao eUICC padrão. O eUICC padrão é determinado pela plataforma para dispositivos com rádio HAL versão 1.2 ou superior e pelo LPA para dispositivos com rádio HAL versões inferiores a 1.2.

Requisitos

Para oferecer suporte a vários eSIMs, o dispositivo deve ter mais de um eUICC, que pode ser um eUICC integrado ou um slot de SIM físico onde eUICCs removíveis podem ser inseridos.

O rádio HAL versão 1.2 ou superior é necessário para suportar vários eSIMs. Radio HAL versão 1.4 e RadioConfig HAL versão 1.2 são recomendados.

Implementação

Para oferecer suporte a vários eSIMs (incluindo eUICCs removíveis ou SIMs programáveis), o LPA deve implementar o EuiccService , que recebe o ID do slot correspondente ao ID do cartão fornecido pelo chamador.

O recurso non_removable_euicc_slots especificado em arrays.xml é uma matriz de números inteiros que representam os IDs de slot dos eUICCs integrados de um dispositivo. Você deve especificar esse recurso para permitir que a plataforma determine se um eUICC inserido é removível ou não.

Aplicativo de operadora para dispositivo com vários eSIMs

Ao criar um aplicativo de operadora para um dispositivo com vários eSIMs, use o método createForCardId no EuiccManager para criar um objeto EuiccManager que é fixado em um determinado ID de cartão. O ID do cartão é um valor inteiro que identifica exclusivamente um UICC ou um eUICC no dispositivo.

Para obter o ID do cartão para o eUICC padrão do dispositivo, use o método getCardIdForDefaultEuicc no TelephonyManager . Este método retorna UNSUPPORTED_CARD_ID se a versão do rádio HAL for inferior a 1.2 e retorna UNINITIALIZED_CARD_ID se o dispositivo não tiver lido o eUICC.

Você também pode obter IDs de cartão de getUiccCardsInfo e getUiccSlotsInfo (API do sistema) em TelephonyManager e getCardId em SubscriptionInfo .

Quando um objeto EuiccManager é instanciado com um ID de cartão específico, todas as operações são direcionadas para o eUICC com esse ID de cartão. Se o eUICC se tornar inacessível (por exemplo, quando for desativado ou removido) EuiccManager não funcionará mais.

Você pode usar os exemplos de código a seguir para criar um aplicativo de operadora.

Exemplo 1: obter assinatura ativa e instanciar 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);

Exemplo 2: iterar por meio de UICCs e instanciar EuiccManager para um eUICC removível

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

Validação

O AOSP não vem com uma implementação de LPA e não se espera que você tenha um LPA disponível em todas as versões do Android (nem todo telefone suporta eSIM). Por esse motivo, não há casos de teste CTS de ponta a ponta. No entanto, os casos de teste básicos estão disponíveis no AOSP para garantir que as APIs eUICC expostas sejam válidas nas compilações do Android.

Você deve garantir que as compilações passem nos seguintes casos de teste CTS (para APIs públicas): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts .

As operadoras que implementam um aplicativo de operadora devem passar por seus ciclos internos normais de garantia de qualidade para garantir que todos os recursos implementados estejam funcionando conforme o esperado. No mínimo, o aplicativo da operadora deve ser capaz de listar todos os perfis de assinatura pertencentes à mesma operadora, baixar e instalar um perfil, ativar um serviço no perfil, alternar entre perfis e excluir perfis.

Se você estiver fazendo seu próprio LPA, deverá passar por testes muito mais rigorosos. Você deve trabalhar com seu fornecedor de modem, chip eUICC ou fornecedor eSIM OS, fornecedores SM-DP+ e operadoras para resolver problemas e garantir a interoperabilidade de seu LPA dentro da arquitetura RSP. Uma boa quantidade de testes manuais é inevitável. Para obter a melhor cobertura de teste, você deve seguir o Plano de Teste GSMA SGP.23 RSP .