A tecnologia de chip incorporado (eSIM ou eUICC) permite que usuários de dispositivos móveis façam o download de um perfil de operadora e ativem o serviço dela sem precisar de um chip 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, o framework do Android fornece APIs padrão para acessar o eSIM e gerenciar perfis de assinatura nele. Com essas APIs eUICC (link em inglês), terceiros podem desenvolver os próprios apps de operadora e assistentes de perfil local (LPAs, na sigla em inglês) em dispositivos Android compatíveis com eSIM.
O LPA é um app independente do sistema que precisa ser incluído na imagem de build do Android. O gerenciamento dos perfis no eSIM geralmente é feito pela LPA, já que ela serve como uma ponte entre o SM-DP+ (serviço remoto que prepara, armazena e entrega pacotes de perfil aos dispositivos) e o chip eUICC. O APK da LPA pode incluir um componente de interface, chamado de interface da LPA ou LUI, para fornecer um local central para o usuário final gerenciar todos os perfis de assinatura incorporados. O framework do Android descobre e se conecta automaticamente à melhor LPA disponível e encaminha todas as operações de eUICC por uma instância de LPA.
Figura 1. Arquitetura RSP simplificada
Operadoras de rede móvel interessadas em criar um app da operadora podem consultar
as APIs em
EuiccManager
,
que oferece 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 app do sistema LPA, será necessário
estender
EuiccService
para que o framework Android se conecte aos seus serviços LPA. Além disso, use as APIs em
EuiccCardManager
,
que fornecem funções ES10x com base no GSMA RSP v2.0.
Essas funções são usadas para emitir comandos ao chip eUICC, como
prepareDownload()
, loadBoundProfilePackage()
, retrieveNotificationList()
e resetMemory()
.
As APIs em
EuiccManager
exigem um app LPA implementado corretamente para funcionar, e o caller das APIs
EuiccCardManager
precisa ser um LPA. Isso é aplicado pelo framework do Android.
Dispositivos com o Android 10 ou mais recente podem oferecer suporte a dispositivos com vários eSIMs. Para mais informações, consulte Compatibilidade com vários eSIMs.
Criar um app de operadora
As APIs eUICC no Android 9 permitem que operadoras de rede móvel criem apps com a marca da operadora para gerenciar os perfis diretamente. Isso inclui baixar e excluir perfis de assinatura de propriedade da operadora, além de mudar para um perfil de propriedade de uma operadora.
EuiccManager
EuiccManager
é o ponto de entrada principal para que os apps interajam com a
LPA. Isso inclui apps da operadora que fazem o download, excluem e mudam para
assinaturas de propriedade da operadora. Isso também inclui o app do sistema LUI, que
fornece um local/interface central para gerenciar todas as assinaturas incorporadas e
pode ser um app separado daquele que fornece o EuiccService
.
Para usar as APIs públicas, um app da operadora precisa primeiro receber a instância de
EuiccManager
por Context#getSystemService
:
EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
Verifique se o eSIM é compatível com o dispositivo antes de realizar qualquer
operação com eSIM. Em geral, EuiccManager#isEnabled()
retorna true
se o
recurso android.hardware.telephony.euicc
estiver definido e um pacote da LPA estiver
presente.
if (mgr == null || !mgr.isEnabled()) {
return;
}
Para saber mais sobre o hardware do eUICC e a versão do SO do eSIM:
EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();
Muitas APIs, como downloadSubscription()
e switchToSubscription()
, usam callbacks PendingIntent
, já que podem levar segundos ou até minutos para serem concluídas.
PendingIntent
é enviado com um código de resultado no espaço EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_
, que fornece códigos de erro definidos pelo framework, bem como um código de resultado detalhado arbitrário propagado do LPA como EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, permitindo que o app da operadora rastreie para fins de registro/depuração. O callback PendingIntent
precisa ser BroadcastReceiver
.
Para baixar uma assinatura disponível para download (criada com um código de ativação ou um QR code):
// Register receiver.
static final String ACTION_DOWNLOAD_SUBSCRIPTION = "download_subscription";
static final String LPA_DECLARED_PERMISSION
= "com.your.company.lpa.permission.BROADCAST";
BroadcastReceiver receiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (!action.equals(intent.getAction())) {
return;
}
resultCode = getResultCode();
detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
0 /* defaultValue*/);
// If the result code is a resolvable error, call startResolutionActivity
if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR) {
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.startResolutionActivity(
activity,
0 /* requestCode */,
intent,
callbackIntent);
}
resultIntent = intent;
}
};
context.registerReceiver(receiver,
new IntentFilter(ACTION_DOWNLOAD_SUBSCRIPTION),
LPA_DECLARED_PERMISSION /* broadcastPermission*/,
null /* handler */);
// Download subscription asynchronously.
DownloadableSubscription sub = DownloadableSubscription
.forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action).setPackage(context.getPackageName());
PendingIntent callbackIntent = PendingIntent.getBroadcast(
getContext(), 0 /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.downloadSubscription(sub, true /* switchAfterDownload */,
callbackIntent);
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 usando o ID dela:
// 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);
Para uma lista completa de APIs EuiccManager
e exemplos de código, consulte
APIs de eUICC.
Erros solucionáveis
Em alguns casos, 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 um código de confirmação da operadora
é necessário. Ou switchToSubscription
pode falhar se o app da operadora tiver privilégios sobre o perfil de destino (ou seja, a operadora é proprietária do perfil), mas não tiver privilégios sobre o perfil ativado no momento. Por isso, é necessário o consentimento do usuário.
Nesses casos, o callback do autor da chamada é chamado com
EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
. O callback
Intent
contém extras internos para que, quando o autor da chamada o transmitir para
EuiccManager#startResolutionActivity
,
a resolução possa ser solicitada pela LUI. Usando o código de confirmação como
exemplo novamente,
EuiccManager#startResolutionActivity
aciona uma tela da LUI que permite ao usuário inserir um código de confirmação;
depois que o código é inserido, a operação de download é retomada. Essa abordagem
oferece ao app da operadora controle total sobre quando a interface é mostrada, mas dá
ao LPA/LUI um método extensível para adicionar novas soluções de problemas
recuperáveis pelo usuário no futuro sem precisar que os apps clientes mudem.
O Android 9 define estes erros solucionáveis em
EuiccService
,
que a LUI precisa processar:
/**
* 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 app que chama EuiccManager
para baixar perfis em um dispositivo, seu perfil deverá incluir regras de
privilégio da operadora correspondentes ao app nos metadados. Isso acontece porque os perfis de assinatura de diferentes operadoras podem coexistir no eUICC de um dispositivo, e cada app de operadora só pode acessar os perfis pertencentes a ela. Por exemplo, a operadora A não pode baixar, ativar ou desativar um perfil da operadora B.
Para garantir que um perfil só possa ser acessado pelo proprietário, o Android usa um mecanismo para
conceder privilégios especiais ao app do proprietário do perfil (ou seja, o app da operadora). A plataforma
Android carrega os certificados armazenados no arquivo de regras de acesso
(ARF) do perfil e concede permissão aos apps assinados por esses certificados para fazer chamadas
para APIs EuiccManager
. Confira abaixo o processo geral:
- O operador assina o APK do app da operadora. A ferramenta apksigner anexa o certificado de chave pública ao APK.
O operador/SM-DP+ prepara um perfil e os metadados dele, que incluem um ARF com:
- Assinatura (SHA-1 ou SHA-256) do certificado de chave pública do app da operadora (obrigatório)
- Nome do pacote do app da operadora (altamente recomendado)
O app da operadora tenta realizar uma operação eUICC com a API
EuiccManager
.A plataforma Android verifica se o hash SHA-1 ou SHA-256 do certificado do app de chamada corresponde à assinatura do certificado obtido do ARF do perfil de destino. Se o nome do pacote do app da operadora estiver incluído no ARF, ele também precisará corresponder ao nome do pacote do app que fez a chamada.
Depois que a assinatura e o nome do pacote (se incluído) forem verificados, o privilégio da operadora será concedido ao app autor da chamada no perfil de destino.
Como os metadados do perfil podem estar disponíveis fora do perfil em si (para que o LPA possa recuperar os metadados do perfil do SM-DP+ antes do download ou do ISD-R quando o perfil estiver desativado), eles precisam conter as mesmas regras de privilégio da operadora do perfil.
O SO da eUICC e o SM-DP+ precisam oferecer suporte a uma tag proprietária BF76
nos metadados do perfil. O conteúdo da tag precisa ser as mesmas regras de privilégio da operadora retornadas
pelo applet de regra de acesso (ARA) definido em
Privilégios da 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 mais detalhes sobre a assinatura de apps, consulte Assinar o app. Para mais detalhes sobre os privilégios da operadora, consulte Privilégios da operadora UICC.
Criar um app assistente de perfil local
Os fabricantes de dispositivos podem implementar o próprio assistente de perfil local (LPA), que precisa ser conectado às APIs Euicc do Android. As seções a seguir oferecem uma breve visão geral de como criar um app LPA e integrá-lo ao sistema Android.
Requisitos de hardware/modem
A LPA e o SO do eSIM no chip eUICC precisam ser compatíveis com pelo menos GSMA RSP (Remote SIM Provisioning) v2.0 ou v2.2. Também é recomendável usar servidores SM-DP+ e SM-DS com uma versão correspondente do RSP. Para uma arquitetura RSP detalhada, consulte GSMA SGP.21 RSP Architecture Specification (em inglês).
Além disso, para integrar com as APIs eUICC no Android 9, o modem do dispositivo precisa enviar recursos do 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
AIDL IRadioConfig v1.0:
getAllowedCarriers
O LPA do Google precisa saber o status de bloqueio da operadora para 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 chip e depois perceber que o dispositivo está bloqueado para uma operadora diferente.
Os fornecedores ou OEMs precisam implementar a API IRadioSim.getAllowedCarriers()HAL.
A RIL / modem do fornecedor precisa preencher o status de bloqueio e o carrierId da operadora em que o dispositivo está bloqueado como parte da API IRadioSimResponse.getAllowedCarriersResponse()HAL.
O modem precisa reconhecer o eSIM com o perfil de inicialização padrão ativado como um chip válido e manter a energia do chip ligada.
Para dispositivos com o Android 10, é necessário definir uma matriz de ID de slot eUICC não removível. 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 uma lista completa de requisitos de modem, consulte Requisitos de modem para suporte a eSIM.
EuiccService
Uma LPA consiste em dois componentes separados (ambos podem ser implementados no mesmo APK): o back-end da LPA e a interface da LPA ou LUI.
Para implementar o back-end da LPA, estenda
EuiccService
e declare esse serviço no arquivo de manifesto. O serviço precisa exigir a permissão
android.permission.BIND_EUICC_SERVICE
do sistema para garantir que apenas
o sistema possa se vincular a ele. O serviço também precisa incluir um filtro de intent com
a ação android.service.euicc.EuiccService
. A prioridade do filtro de intent
precisa ser definida como um valor diferente de zero caso várias implementações estejam
presentes no dispositivo. 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, o framework do Android determina o LPA ativo e interage com ele conforme necessário para oferecer suporte às APIs eUICC do Android. O PackageManager
é consultado para
todos os apps 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 maior prioridade é selecionado. Se nenhum serviço for encontrado, o suporte
do LPA será desativado.
Para implementar a LUI, você precisa fornecer uma atividade para as seguintes ações:
android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS
android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION
Assim como o serviço, cada atividade precisa exigir a permissão de sistema
android.permission.BIND_EUICC_SERVICE
. Cada um precisa ter um
filtro de intent com a ação apropriada, a
categoria android.service.euicc.category.EUICC_UI
e uma prioridade diferente de zero.
Uma lógica semelhante é usada para escolher as implementações dessas atividades, assim como a implementação de
EuiccService
.
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 (por exemplo, um que implementa
EuiccService
e outro que fornece atividades de LUI) é uma escolha de design.
EuiccCardManager
EuiccCardManager
é a interface para comunicação com o chip eSIM. Ele
fornece funções ES10 (conforme descrito na especificação RSP da GSMA) e processa os
comandos de solicitação/resposta APDU de baixo nível, bem como a análise ASN.1.
EuiccCardManager
é uma API do sistema e só pode ser chamada por apps com privilégios do sistema.
Figura 2. O app da operadora e o LPA usam APIs Euicc
As APIs de operação de perfil por EuiccCardManager
exigem que o autor da chamada seja
um LPA. Isso é aplicado pelo framework do Android. Isso significa que o caller precisa
estender EuiccService
e ser declarado no arquivo de manifesto, conforme descrito nas
seções anteriores.
Assim como EuiccManager
, para usar as APIs EuiccCardManager
, seu LPA precisa
primeiro receber a instância de EuiccCardManager
usando
Context#getSystemService
:
EuiccCardManager cardMgr = (EuiccCardManager) context.getSystemService(Context.EUICC_CARD_SERVICE);
Em seguida, para acessar todos os perfis na 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 vincula a EuiccCardController
(que é executado no processo do
telefone) por uma interface AIDL, e cada método EuiccCardManager
recebe o callback do processo do telefone por uma interface AIDL
diferente e dedicada. Ao usar as APIs EuiccCardManager
, o chamador (LPA) precisa fornecer um objeto
Executor
pelo qual o callback é invocado. Esse objeto Executor
pode ser executado em uma única linha de execução ou em um pool de linhas de execução de sua escolha.
A maioria das APIs do EuiccCardManager
tem o mesmo padrão de uso. Por exemplo, para carregar um pacote de perfil vinculado na 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 conseguir 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 especificados:
...
cardMgr.listNotifications(eid,
EuiccNotification.Event.INSTALL
| EuiccNotification.Event.DELETE /* events */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Ativar um perfil de eSIM usando um app da operadora
Em dispositivos com o Android 9 ou versões mais recentes, é possível usar um app da operadora para ativar
o eSIM e fazer o download de perfis. O app da operadora pode fazer o download de perfis
chamando
downloadSubscription
diretamente ou fornecendo um código de ativação para o LPA.
Quando um app da operadora faz o download de um perfil chamando
downloadSubscription
,
a chamada exige que o app possa gerenciar o perfil usando uma BF76
tag de metadados
que codifica regras de privilégio da operadora para o
perfil. Se um perfil não tiver uma tag BF76
ou se a tag BF76
não corresponder à assinatura do app de operadora de chamadas, o download será rejeitado.
A seção abaixo descreve como ativar um eSIM usando um app da operadora e um código de ativação.
Ativar o eSIM usando um código de ativação
Ao usar um código de ativação para ativar um perfil de eSIM, o LPA busca
um código de ativação no
app da operadora e faz o download do perfil. Esse fluxo pode ser iniciado pelo LPA, que controla todo o fluxo da interface. Isso significa que nenhuma interface do app da operadora é mostrada. Essa abordagem ignora a verificação da tag BF76
, e os operadores de rede não precisam implementar todo o fluxo da interface de ativação do eSIM, incluindo o download de um perfil de eSIM e o tratamento de erros.
Definir o serviço de provisionamento de eUICC da operadora
O LPA e o app da operadora se comunicam por duas interfaces
AIDL:
ICarrierEuiccProvisioningService
e IGetActivationCodeCallback
. O app da operadora precisa implementar uma interface ICarrierEuiccProvisioningService
e expô-la na declaração do manifesto.
A LPA precisa se vincular a ICarrierEuiccProvisioningService
e implementar
IGetActivationCodeCallback
. Para mais informações sobre como implementar e
expor uma interface AIDL, consulte Como definir uma interface AIDL.
Para definir as interfaces AIDL, crie os seguintes arquivos AIDL para os apps da LPA e 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 ICarrierEuiccProvisioningService
do app da operadora,
o LPA precisa 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);
}
Depois de vincular à implementação ICarrierEuiccProvisioningService
do app da operadora, a LPA chama getActivationCode
ou
getActivationCodeForEid
para receber o código de ativação do app da operadora
transmitindo 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 um app de operadora
Para que a LPA se vincule ao app da operadora, ele precisa copiar ICarrierEuiccProvisioningService.aidl
e IGetActivationCodeCallback.aidl
para seu projeto e declarar o serviço ICarrierEuiccProvisioningService
no arquivo AndroidManifest.xml
. O serviço precisa exigir a permissão
android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
do sistema para garantir
que apenas o LPA, um app com privilégios do sistema, possa se vincular a ele. O serviço também precisa 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 app da operadora AIDL, crie um serviço, estenda a classe Stub
e implemente os métodos getActivationCode
e getActivationCodeForEid
. Em seguida, a LPA pode chamar qualquer um dos métodos para buscar o código de ativação do perfil. O app da operadora precisa responder chamando
IGetActivationCodeCallback#onSuccess
com o código de ativação se ele foi
buscado do servidor da operadora com sucesso. Se não for bem-sucedida, o app da operadora
vai 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); } } }
Iniciar a interface do app da operadora no fluxo de ativação de LPA
Em dispositivos com o Android 11 e versões mais recentes, o LPA pode iniciar a interface de um app da operadora. Isso é útil porque um app de operadora pode exigir mais informações 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 os números de telefone ou realizar outros serviços de portabilidade.
Este é o processo para iniciar a interface de um app de operadora no LPA:
O LPA inicia o fluxo de ativação do app da operadora enviando a intent
android.service.euicc.action.START_CARRIER_ACTIVATION
para o pacote do app da operadora que contém a ação. O receptor do app da operadora precisa ser protegido na declaração do manifesto comandroid:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
para evitar o recebimento de intents de apps que não sã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);
O app da operadora faz o trabalho usando a própria interface. Por exemplo, fazer login do usuário ou enviar solicitações HTTP para o back-end da operadora.
O app da operadora responde à LPA chamando
setResult(int, Intent)
efinish()
.- Se o app da operadora responder com
RESULT_OK
, o LPA vai continuar o fluxo de ativação. Se o app da operadora determinar que o usuário precisa ler um QR code em vez de permitir que o LPA vincule o serviço do app da operadora, o app da operadora vai responder ao LPA usandosetResult(int, Intent)
comRESULT_OK
e uma instânciaIntent
que contém o extra booleanoandroid.telephony.euicc.extra.USE_QR_SCANNER
definido comotrue
. Em seguida, a LPA verifica o extra e inicia o scanner de QR code em vez de vincular a implementaçãoICarrierEuiccProvisioningService
do app da operadora. - Se o app da operadora falhar ou responder com
RESULT_CANCELED
(este é o código de resposta padrão), a LPA vai cancelar o fluxo de ativação do eSIM. - Se o app da operadora responder com algo diferente de
RESULT_OK
ouRESULT_CANCELED
, a LPA vai tratar isso como um erro.
Por motivos de segurança, o LPA não deve aceitar diretamente um código de ativação fornecido na intent de resultado para garantir que chamadores que não sejam do LPA não possam receber um código de ativação do app da operadora.
- Se o app da operadora responder com
Iniciar o fluxo de ativação de LPA em um app de operadora
A partir do Android 11, os apps das operadoras podem usar APIs eUICC para iniciar uma LUI para ativação de 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. Em seguida, a LPA envia uma transmissão quando a ativação do perfil do eSIM é concluída.
A LPA precisa declarar uma atividade que inclua um filtro de intent com a ação
android.service.euicc.action.START_EUICC_ACTIVATION
. A prioridade do filtro de intent precisa ser definida como um valor diferente de zero caso haja várias implementações no dispositivo. 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>
O app da operadora faz o trabalho usando a própria interface. Por exemplo, fazer login do usuário ou enviar solicitações HTTP para o back-end da operadora.
Nesse momento, o app da operadora precisa estar pronto para fornecer um código de ativação pela implementação
ICarrierEuiccProvisioningService
. O app da operadora inicia o LPA chamandostartActivityForResult(Intent, int)
com a açãoandroid.telephony.euicc.action.START_EUICC_ACTIVATION
. A LPA também verifica o extra booleanoandroid.telephony.euicc.extra.USE_QR_SCANNER
. Se o valor fortrue
, o LPA vai iniciar o leitor de QR code para que o usuário possa ler o QR code do perfil.No lado do LPA, ele se vincula à implementação
ICarrierEuiccProvisioningService
do app da operadora para buscar o código de ativação e fazer o download do perfil correspondente. O LPA mostra todos os elementos de interface necessários durante o download, como uma tela de carregamento.Quando o fluxo de ativação de LPA é concluído, o LPA responde ao app da operadora com um código de resultado, que o app da operadora processa em
onActivityResult(int, int, Intent)
.- Se o LPA conseguir baixar o novo perfil de eSIM, ele
vai responder com
RESULT_OK
. - Se o usuário cancelar a ativação do perfil de eSIM no LPA, ele
vai responder com
RESULT_CANCELED
. - Se o LPA responder com algo diferente de
RESULT_OK
ouRESULT_CANCELED
, o app da operadora vai tratar isso como um erro.
Por motivos de segurança, o LPA não aceita um código de ativação diretamente na intent fornecida para garantir que chamadores que não sejam do LPA não possam receber o código de ativação do app da operadora.
- Se o LPA conseguir baixar o novo perfil de eSIM, ele
vai responder com
Suporte a vários eSIMs
Para dispositivos com Android 10 ou versões mais recentes, a classe
EuiccManager
é compatível com dispositivos
com vários eSIMs. Os dispositivos com um único eSIM que estão sendo atualizados para o
Android 10
não exigem nenhuma modificação na implementação da LPA, já que a plataforma
associa automaticamente a instância EuiccManager
ao eUICC padrão. A
eUICC padrão é determinada pela plataforma para dispositivos com a versão 1.2 ou mais recente da HAL de rádio e pela LPA para dispositivos com versões da HAL de rádio anteriores a
1.2.
Requisitos
Para oferecer suporte a vários eSIMs, o dispositivo precisa ter mais de um eUICC, que pode ser um eUICC integrado ou um slot de SIM físico em que eUICCs removíveis podem ser inseridos.
A versão 1.2 ou mais recente do HAL de rádio é necessária para oferecer suporte a vários eSIMs. Recomendamos as versões 1.4 e 1.2 da HAL Radio e da HAL RadioConfig, respectivamente.
Implementação
Para oferecer suporte a vários eSIMs (incluindo eUICCs removíveis ou SIMs programáveis), a
LPA precisa implementar
EuiccService
,
que recebe o ID do slot correspondente ao ID do cartão fornecido pelo autor da chamada.
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. É necessário especificar esse recurso para permitir que a plataforma determine
se um eUICC inserido é removível ou não.
App da operadora para dispositivo com vários eSIMs
Ao criar um app de operadora para um dispositivo com vários eSIMs, use o método
createForCardId
em EuiccManager
para criar um objeto EuiccManager
fixado em um
ID de cartão específico. O ID do cartão é um valor inteiro que identifica de maneira exclusiva um UICC
ou um eUICC no dispositivo.
Para receber o ID do cartão do eUICC padrão do dispositivo, use o método
getCardIdForDefaultEuicc
em TelephonyManager
. Esse método retorna
UNSUPPORTED_CARD_ID
se a versão do HAL de rádio for anterior a 1.2 e retorna
UNINITIALIZED_CARD_ID
se o dispositivo não tiver lido o eUICC.
Você também pode receber 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. Se a eUICC ficar
inacessível (por exemplo, quando ela for desligada ou removida), o EuiccManager
não
vai mais funcionar.
Use os exemplos de código a seguir para criar um app da operadora.
Exemplo 1: receber a 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 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 é esperado que você tenha um LPA disponível em todos os builds do Android (nem todos os smartphones são compatíveis com eSIM). Por esse motivo, não há casos de teste CTS de 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 em builds do Android.
Verifique se os builds passam nos seguintes casos de teste do CTS (para APIs públicas): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts.
As operadoras que implementam um app precisam passar pelos ciclos normais internos de controle de qualidade para garantir que todos os recursos implementados estejam funcionando como esperado. No mínimo, o app da operadora precisa listar todos os perfis de assinatura de propriedade da mesma operadora, baixar e instalar um perfil, ativar um serviço no perfil, alternar entre perfis e excluir perfis.
Se você estiver criando sua própria LPA, faça testes muito mais rigorosos. Trabalhe com o fornecedor do modem, do chip eUICC ou do sistema operacional eSIM, com os fornecedores de SM-DP+ e com as operadoras para resolver problemas e garantir a interoperabilidade da LPA na arquitetura RSP. Uma boa quantidade de testes manuais é inevitável. Para ter a melhor cobertura de teste, siga o Plano de teste SGP.23 RSP da GSMA.