Implementando eSIM

A tecnologia SIM incorporada (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 impulsionada 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 independente 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 ponte entre o SM-DP+ (serviço remoto que prepara, armazena e entrega pacotes de perfis aos dispositivos) e o chip eUICC. O APK LPA pode incluir opcionalmente um componente de UI, chamado LPA UI ou LUI, para fornecer um local central para o usuário final gerenciar todos os perfis de assinatura incorporados. A estrutura Android descobre e se conecta automaticamente ao melhor LPA disponível e roteia todas as operações eUICC por meio de uma instância 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 de sistema LPA, deverá estender EuiccService para a estrutura do Android para se conectar aos seus serviços LPA. Além disso, você deve usar as APIs do EuiccCardManager , que fornecem funções ES10x baseadas no 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 devidamente implementado para funcionar e o chamador das APIs EuiccCardManager deve ser um LPA. Isso é imposto pela estrutura Android.

Dispositivos com Android 10 ou superior podem oferecer suporte a 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 redes móveis criem aplicativos da marca da operadora para gerenciar seus perfis diretamente. Isso inclui baixar e excluir perfis de assinatura de propriedade da operadora, bem como mudar para um perfil de propriedade de uma operadora.

EuiccManager

EuiccManager é o principal ponto de entrada para aplicativos interagirem com o LPA. Isso inclui aplicativos de operadoras que baixam, excluem e mudam para assinaturas de propriedade da operadora. Isso também inclui o aplicativo do sistema LUI, que fornece uma localização/IU 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 do 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.

if (mgr == null || !mgr.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*/);

                // 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);
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent,
        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.downloadSubscription(sub, true /* switchAfterDownload */,
        callbackIntent);

Defina e use a permissão em AndroidManifest.xml :

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

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 | PendingIntent.FLAG_MUTABLE);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);

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

Erros solucionáveis

Existem 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 poderá falhar se os metadados do perfil indicarem que um código de confirmação da operadora é necessário. Ou switchToSubscription poderá falhar se o aplicativo da operadora tiver privilégios de operadora sobre o perfil de destino (ou seja, a operadora possui o perfil), mas não tiver privilégios de operadora sobre o perfil atualmente habilitado e, portanto, é necessário o consentimento do usuário.

Para esses casos, o retorno de chamada do chamador é chamado com EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR . A Intent de retorno de chamada contém extras internos de forma que quando o chamador a transmite 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 IU é mostrada, mas fornece ao LPA/LUI um método extensível para adicionar novo tratamento de problemas recuperáveis ​​pelo usuário no futuro, sem a necessidade de alteração dos aplicativos cliente.

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

/**
 * 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ê é uma operadora que está desenvolvendo seu próprio aplicativo de operadora que chama 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 da operadora só deve ter permissão para acessar os perfis pertencentes a essa operadora. Por exemplo, a operadora A não deve ser capaz de baixar, ativar ou desativar um perfil pertencente à 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, ao aplicativo da operadora). A plataforma Android carrega certificados armazenados no arquivo de regras de acesso (ARF) do perfil e concede permissão aos aplicativos assinados por esses certificados para fazer chamadas para APIs EuiccManager . O processo de alto nível é descrito abaixo:

  1. Operadora assina APK do app da operadora; a ferramenta apksigner anexa o certificado de chave pública ao APK.
  2. A Operadora/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 (altamente recomendado)
  3. O aplicativo Carrier tenta realizar uma operação eUICC por meio da API EuiccManager .

  4. A plataforma Android verifica se 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. Após a verificação da assinatura e do nome do pacote (se incluído), o privilégio da operadora é concedido ao aplicativo chamador no 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 do download do perfil ou do ISD-R quando o perfil estiver desativado), eles devem conter as mesmas regras de privilégio da operadora como no perfil.

O sistema operacional eUICC e SM-DP+ devem suportar uma tag proprietária BF76 nos metadados do perfil. O conteúdo da tag deve ter as mesmas regras de privilégio de operadora retornadas pelo miniaplicativo de regras de acesso (ARA) definido em UICC Carrier Privileges :

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 assinatura de aplicativos, consulte Assine seu aplicativo . Para obter detalhes sobre privilégios de operadora, consulte Privilégios de operadora UICC .

Criando um aplicativo assistente de perfil local

Você pode implementar seu próprio assistente de perfil local (LPA), que deve estar conectado às APIs 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 sistema operacional eSIM 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 obter uma arquitetura RSP detalhada, consulte Especificação de arquitetura RSP GSMA SGP.21 .

Além disso, para integração 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

  • IRadioConfig AIDL v1.0: getAllowedCarriers

    A LPA do Google precisa saber o status de bloqueio da operadora para poder permitir o download ou a transferência do eSIM apenas para a operadora permitida. Caso contrário, os usuários podem acabar baixando e transferindo um SIM e mais tarde perceber que o dispositivo está bloqueado para uma operadora diferente.

    • Fornecedores ou OEMs devem implementar a API IRadioSim.getAllowedCarriers()HAL.

    • O RIL/Modem do fornecedor deverá preencher o status de bloqueio e orierId da operadora onde o dispositivo está bloqueado como parte da API IRadioSimResponse.getAllowedCarriersResponse()HAL.

O modem deve reconhecer o eSIM com o perfil de inicialização padrão habilitado 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 .

EuiccServiço

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

Para implementar o backend LPA, você deve estender EuiccService e declarar este 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 somente o sistema possa se vincular a ele. O serviço também deve incluir um filtro de intenções com a ação android.service.euicc.EuiccService . A prioridade do filtro de intenção deve ser definida para um valor diferente de zero caso múltiplas 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 maior prioridade é selecionado. Se nenhum serviço for encontrado, o suporte LPA será desativado.

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 acontece com o 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, assim 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 UI que implementa essas telas pode vir de um APK diferente daquele que implementa EuiccService . Ter um único APK ou vários APKs (por exemplo, um que implemente EuiccService e outro que forneça atividades LUI) é uma escolha de design.

EuiccCardManager

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

Aplicativos de operadora, LPA e APIs Euicc

Figura 2. Tanto o aplicativo da operadora quanto o LPA usam APIs Euicc

As APIs de operação de perfil por meio EuiccCardManager exigem que o chamador seja um LPA. Isso é imposto pela estrutura Android. Isso significa que o chamador deve estender EuiccService e ser declarado no 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 do EuiccCardManager por meio 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 telefônico) por meio de uma interface AIDL, e cada método EuiccCardManager recebe seu retorno de chamada do processo telefônico por meio de uma interface AIDL dedicada diferente. Ao utilizar APIs EuiccCardManager , o chamador (LPA) deve fornecer um objeto Executor através 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 possuem 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 mudar 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 da 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 à 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 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 no aplicativo da operadora e baixa o perfil. Esse fluxo pode ser iniciado pelo LPA e o LPA pode controlar todo o fluxo da UI, o que significa que nenhuma UI do aplicativo da operadora é mostrada. Essa abordagem ignora a verificação da tag BF76 , e as operadoras de rede não precisam implementar todo o fluxo da interface 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 LPA e o aplicativo 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 . A LPA deve vincular-se a ICarrierEuiccProvisioningService e implementar IGetActivationCodeCallback . Para obter mais informações sobre como implementar e expor uma interface AIDL, consulte Definição e interface AIDL .

Para definir as interfaces AIDL, crie os seguintes arquivos AIDL para os aplicativos LPA e de 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-se à implementação ICarrierEuiccProvisioningService do aplicativo da operadora, a 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 de ICarrierEuiccProvisioningService do aplicativo da operadora, a LPA chama getActivationCode ou getActivationCodeForEid para obter o código de ativação do aplicativo da operadora, passando a implementação da classe 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 se vincule 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 de 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 da 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 deverá responder chamando IGetActivationCodeCallback#onSuccess com o código de ativação se o código tiver sido obtido com êxito do servidor da operadora. 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 da LPA

Em dispositivos com Android 11 e versões posteriores, o LPA pode iniciar a IU de um aplicativo da 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 à 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 na LPA:

  1. O LPA inicia o fluxo de ativação do aplicativo da operadora enviando a intenção 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 intenções 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 IU. Por exemplo, fazer login do usuário ou enviar solicitações HTTP para o backend 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 escanear 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 android.telephony.euicc.extra.USE_QR_SCANNER definido como true . O LPA então 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 (este é 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 tratará isso como um erro.

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

Iniciando o fluxo de ativação de 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. Este método apresenta a IU 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. A LPA deve declarar uma atividade incluindo um filtro de intent com a ação android.service.euicc.action.START_EUICC_ACTIVATION . A prioridade do filtro de intenção deve ser definida para um valor diferente de zero caso múltiplas 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 IU. Por exemplo, fazer login do usuário ou enviar solicitações HTTP para o backend da operadora.

  3. Neste 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 inicia o scanner QR para permitir que o usuário leia o código QR do perfil.

  4. No lado do LPA, o LPA se liga à 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 UI 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 trata em onActivityResult(int, int, Intent) .

    1. Se o LPA conseguir baixar o novo perfil eSIM, ele responderá com RESULT_OK .
    2. Caso o usuário cancele a ativação do perfil eSIM na LPA, ele responderá com RESULT_CANCELED .
    3. Se a 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, a LPA não aceita um código de ativação diretamente na intenção fornecida para garantir que quem não faz a chamada não consiga 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 oferece suporte a dispositivos com vários eSIMs. 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 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 suportar vários eSIMs, o dispositivo deve ter mais de um eUICC, que pode ser um eUICC integrado ou um slot 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 suportar vários eSIMs (incluindo eUICCs removíveis ou SIMs programáveis), o LPA deve implementar 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 representa 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 dispositivos 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 fixado em um determinado ID de cartão. O ID do cartão é um valor inteiro que identifica exclusivamente um UICC ou eUICC no dispositivo.

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

Você também pode obter IDs de cartão em 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 ficar inacessível (por exemplo, quando for desligado 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: Obtenha assinatura ativa e instancie 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 através 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 oferece suporte a eSIM). Por esse motivo, não existem casos de teste CTS ponta a ponta. No entanto, 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 de sistema operacional eSIM, fornecedores de 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 .