Технология встроенной SIM-карты (eSIM или eUICC) позволяет мобильным пользователям загружать профиль оператора и активировать услугу оператора без физической SIM-карты. Это глобальная спецификация, управляемая GSMA, которая обеспечивает удаленную инициализацию SIM-карты (RSP) любого мобильного устройства. Начиная с Android 9, платформа Android предоставляет стандартные API для доступа к eSIM и управления профилями подписки на eSIM. Эти API-интерфейсы eUICC позволяют третьим сторонам разрабатывать собственные приложения для операторов связи и помощников по работе с локальными профилями (LPA) на устройствах Android с поддержкой eSIM.
LPA — это автономное системное приложение, которое должно быть включено в образ сборки Android. Управление профилями на eSIM обычно осуществляется LPA, поскольку он служит мостом между SM-DP+ (удаленная служба, которая подготавливает, хранит и доставляет пакеты профилей на устройства) и микросхемой eUICC. LPA APK может дополнительно включать компонент пользовательского интерфейса, называемый пользовательским интерфейсом LPA или LUI, чтобы предоставить конечному пользователю центральное место для управления всеми встроенными профилями подписки. Платформа Android автоматически обнаруживает и подключается к лучшему доступному LPA, а также направляет все операции eUICC через экземпляр LPA.
Рисунок 1. Упрощенная архитектура RSP
Операторы мобильных сетей, заинтересованные в создании мобильного приложения, должны обратить внимание на API-интерфейсы в EuiccManager
, которые обеспечивают высокоуровневые операции управления профилями, такие как downloadSubscription()
, switchToSubscription()
и deleteSubscription()
.
Если вы OEM-производитель устройств, заинтересованный в создании собственного системного приложения LPA, вы должны расширить EuiccService
для платформы Android, чтобы подключиться к вашим службам LPA. Кроме того, вы должны использовать API-интерфейсы в EuiccCardManager
, которые предоставляют функции ES10x на основе GSMA RSP v2.0. Эти функции используются для выдачи команд чипу eUICC, таких как prepareDownload()
, loadBoundProfilePackage()
, retrieveNotificationList()
и resetMemory()
.
Для работы API в EuiccManager
требуется правильно реализованное приложение LPA, а вызывающим API EuiccCardManager
должен быть LPA. Это обеспечивается платформой Android.
Устройства под управлением Android 10 или более поздней версии могут поддерживать устройства с несколькими eSIM. Дополнительные сведения см. в разделе Поддержка нескольких карт eSIM .
Делаем приложение оператора
API-интерфейсы eUICC в Android 9 позволяют операторам мобильных сетей создавать фирменные приложения для непосредственного управления своими профилями. Это включает загрузку и удаление профилей подписки, принадлежащих оператору, а также переключение на профиль, принадлежащий оператору.
EuiccManager
EuiccManager
— это основная точка входа для взаимодействия приложений с LPA. Сюда входят приложения оператора, которые загружают, удаляют и переключаются на подписки, принадлежащие оператору. Это также включает в себя системное приложение LUI, которое обеспечивает централизованное расположение/пользовательский интерфейс для управления всеми встроенными подписками и может быть отдельным приложением от того, которое предоставляет EuiccService
.
Чтобы использовать общедоступные API, приложение-носитель должно сначала получить экземпляр EuiccManager
через Context#getSystemService
:
EuiccManager mgr = (EuiccManager) context.getSystemService(Context.EUICC_SERVICE);
Вы должны проверить, поддерживается ли eSIM на устройстве, прежде чем выполнять какие-либо операции с eSIM. EuiccManager#isEnabled()
обычно возвращает значение true
, если функция android.hardware.telephony.euicc
определена и присутствует пакет LPA.
boolean isEnabled = mgr.isEnabled();
if (!isEnabled) {
return;
}
Чтобы получить информацию об оборудовании eUICC и версии ОС eSIM:
EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();
Многие API, такие как downloadSubscription()
и switchToSubscription()
, используют обратные вызовы PendingIntent
, поскольку их выполнение может занять секунды или даже минуты. PendingIntent
отправляется с кодом результата в пространстве EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_
, который предоставляет коды ошибок, определенные платформой, а также произвольный подробный код результата, распространяемый из LPA как EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, что позволяет приложению-перевозчику отслеживать для целей ведения журнала/отладки. Обратный вызов PendingIntent
должен быть BroadcastReceiver
.
Чтобы загрузить данную загружаемую подписку (созданную из кода активации или 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);
Чтобы переключиться на подписку с идентификатором подписки:
// 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);
Полный список API-интерфейсов EuiccManager
и примеры кода см. в разделе API-интерфейсы eUICC .
Устранимые ошибки
В некоторых случаях система не может завершить операцию eSIM, но ошибка может быть устранена пользователем. Например, downloadSubscription
может завершиться ошибкой, если в метаданных профиля указано, что требуется код подтверждения оператора . Или может произойти сбой switchToSubscription
, если приложение оператора связи имеет привилегии оператора над целевым профилем (то есть оператор владеет профилем), но не имеет привилегий оператора над текущим включенным профилем, и, следовательно, требуется согласие пользователя.
В этих случаях обратный вызов вызывающей стороны вызывается с помощью EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
. Intent
обратного вызова содержит внутренние дополнения, поэтому, когда вызывающий объект передает его EuiccManager#startResolutionActivity
, разрешение может быть запрошено через LUI. Например, снова используя код подтверждения, EuiccManager#startResolutionActivity
запускает экран LUI, который позволяет пользователю ввести код подтверждения; после ввода кода операция загрузки возобновляется. Этот подход предоставляет приложению-носителю полный контроль над тем, когда отображается пользовательский интерфейс, но дает LPA/LUI расширяемый метод для добавления новой обработки восстанавливаемых пользователем проблем в будущем без необходимости изменения клиентских приложений.
Android 9 определяет эти устранимые ошибки в EuiccService
, которые должен обрабатывать LUI:
/**
* 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";
Привилегии перевозчика
Если вы являетесь оператором связи, разрабатывающим собственное приложение оператора, которое вызывает EuiccManager
для загрузки профилей на устройство, ваш профиль должен включать в метаданные правила привилегий оператора, соответствующие вашему приложению оператора. Это связано с тем, что профили подписки, принадлежащие разным операторам, могут сосуществовать в eUICC устройства, и каждому приложению оператора должен быть разрешен доступ только к профилям, принадлежащим этому оператору. Например, оператор связи А не должен иметь возможности загружать, включать или отключать профиль, принадлежащий оператору связи Б.
Чтобы профиль был доступен только его владельцу, Android использует механизм предоставления специальных привилегий приложению владельца профиля (то есть приложению-носителю). Платформа Android загружает сертификаты, хранящиеся в файле правил доступа профиля (ARF), и предоставляет приложениям, подписанным этими сертификатами, разрешение на вызовы API EuiccManager
. Процесс высокого уровня описан ниже:
- Оператор подписывает APK приложения оператора; инструмент apksigner прикрепляет сертификат открытого ключа к APK.
Оператор/SM-DP+ подготавливает профиль и его метаданные, которые включают ARF, который содержит:
- Подпись (SHA-1 или SHA-256) сертификата открытого ключа приложения-перевозчика (обязательно)
- Название пакета мобильного приложения (необязательно)
Приложение Carrier пытается выполнить операцию
EuiccManager
.Платформа Android проверяет хэш SHA-1 или SHA-256 сертификата вызывающего приложения на соответствие подписи сертификата, полученного из ARF целевого профиля. Если имя пакета приложения-носителя включено в ARF, оно также должно совпадать с именем пакета вызывающего приложения.
После проверки подписи и имени пакета (если оно включено) привилегия оператора связи предоставляется вызывающему приложению в целевом профиле.
Поскольку метаданные профиля могут быть доступны за пределами самого профиля (чтобы LPA мог получить метаданные профиля из SM-DP+ до загрузки профиля или из ISD-R, когда профиль отключен), они должны содержать те же правила привилегий оператора. как в профиле.
ОС eUICC и SM-DP+ должны поддерживать собственный тег BF76
в метаданных профиля. Содержимое тега должно соответствовать тем же правилам привилегий оператора связи, которые возвращаются апплетом правил доступа (ARA), определенным в привилегиях оператора связи 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
}
}
Дополнительные сведения о подписании приложений см. в разделе Подпишите приложение . Дополнительные сведения о привилегиях оператора см. в разделе Привилегии оператора UICC .
Создание LPA-приложения
Вы можете реализовать свой собственный LPA, который должен быть связан с Android Euicc API. В следующих разделах дается краткий обзор создания приложения LPA и его интеграции с системой Android.
Требования к оборудованию/модему
LPA и ОС eSIM на чипе eUICC должны поддерживать как минимум GSMA RSP (удаленная подготовка SIM-карты) v2.0 или v2.2. Вы также должны планировать использование серверов SM-DP+ и SM-DS с соответствующей версией RSP. Подробную информацию об архитектуре RSP см. в Спецификации архитектуры RSP GSMA SGP.21 .
Кроме того, для интеграции с API-интерфейсами eUICC в Android 9 модем устройства должен отправлять возможности терминала с закодированной поддержкой возможностей eUICC (локальное управление профилями и загрузка профилей). Также необходимо реализовать следующие методы:
- IRadio HAL v1.1:
setSimPower
IRadio HAL v1.2:
getIccCardStatus
IRadioConfig HAL v1.0:
getSimSlotsStatus
Модем должен распознать eSIM с включенным профилем загрузки по умолчанию как действующую SIM-карту и оставить питание SIM-карты включенным.
Для устройств под управлением Android 10 необходимо определить несъемный массив идентификаторов слотов eUICC. Например, см. 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>
Полный список требований к модему см. в разделе Требования к модему для поддержки eSIM .
EuiccService
LPA состоит из двух отдельных компонентов (оба могут быть реализованы в одном APK): серверной части LPA и пользовательского интерфейса LPA или LUI.
Чтобы реализовать серверную часть LPA, вы должны расширить EuiccService
и объявить эту службу в файле манифеста. Службе должно требоваться системное разрешение android.permission.BIND_EUICC_SERVICE
, чтобы гарантировать, что только система может привязаться к ней. Служба также должна включать фильтр намерений с действием android.service.euicc.EuiccService
. Приоритет фильтра намерений должен быть установлен на ненулевое значение, если на устройстве присутствует несколько реализаций. Например:
<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>
Внутри платформа Android определяет активный LPA и взаимодействует с ним по мере необходимости для поддержки API-интерфейсов Android eUICC. PackageManager
запрашивается для всех приложений с разрешением android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
, которое указывает службу для действия android.service.euicc.EuiccService
. Выбирается услуга с наивысшим приоритетом. Если служба не найдена, поддержка LPA отключена.
Чтобы реализовать LUI, вы должны предоставить активность для следующих действий:
-
android.service.euicc.action.MANAGE_EMBEDDED_SUBSCRIPTIONS
-
android.service.euicc.action.PROVISION_EMBEDDED_SUBSCRIPTION
Как и в случае со службой, каждое действие должно требовать системного разрешения android.permission.BIND_EUICC_SERVICE
. У каждого должен быть фильтр намерений с соответствующим действием, категорией android.service.euicc.category.EUICC_UI
и ненулевым приоритетом. Аналогичная логика используется для выбора реализации этих действий, как и при выборе реализации EuiccService
. Например:
<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>
Это означает, что пользовательский интерфейс, реализующий эти экраны, может исходить из APK, отличного от того, который реализует EuiccService
. Иметь один APK или несколько APK (например, один, который реализует EuiccService
, а другой, который предоставляет действия LUI), является выбором дизайна.
EuiccCardManager
EuiccCardManager
— это интерфейс для связи с чипом eSIM. Он предоставляет функции ES10 (как описано в спецификации GSMA RSP) и обрабатывает низкоуровневые команды запроса/ответа APDU, а также синтаксический анализ ASN.1. EuiccCardManager
— это системный API, который может вызываться только приложениями с системными привилегиями.
Рис. 2. И операторское приложение, и LPA используют API-интерфейсы Euicc.
API-интерфейсы операций с профилями через EuiccCardManager
требуют, чтобы вызывающий объект был LPA. Это обеспечивается платформой Android. Это означает, что вызывающая сторона должна расширить EuiccService
и быть объявлена в вашем файле манифеста, как описано в предыдущих разделах.
Подобно EuiccManager
, для использования API EuiccCardManager
ваш LPA должен сначала получить экземпляр EuiccCardManager
через Context#getSystemService
:
EuiccCardManager cardMgr = (EuiccCardManager) context.getSystemService(Context.EUICC_CARD_SERVICE);
Затем, чтобы получить все профили на 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);
Внутри EuiccCardManager
привязывается к EuiccCardController
(который выполняется в процессе телефона) через интерфейс AIDL, и каждый метод EuiccCardManager
получает обратный вызов от процесса телефона через другой выделенный интерфейс AIDL. При использовании API EuiccCardManager
вызывающая сторона (LPA) должна предоставить объект Executor
, через который вызывается обратный вызов. Этот объект Executor
может работать в одном потоке или в пуле потоков по вашему выбору.
Большинство API EuiccCardManager
имеют одинаковую схему использования. Например, чтобы загрузить связанный пакет профиля на eUICC:
...
cardMgr.loadBoundProfilePackage(eid, boundProfilePackage,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Чтобы переключиться на другой профиль с данным ICCID:
...
cardMgr.switchToProfile(eid, iccid, true /* refresh */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Чтобы получить адрес SM-DP+ по умолчанию от чипа eUICC:
...
cardMgr.requestDefaultSmdpAddress(eid, AsyncTask.THREAD_POOL_EXECUTOR,
callback);
Чтобы получить список уведомлений о заданных событиях уведомлений:
...
cardMgr.listNotifications(eid,
EuiccNotification.Event.INSTALL
| EuiccNotification.Event.DELETE /* events */,
AsyncTask.THREAD_POOL_EXECUTOR, callback);
Активация профиля eSIM через приложение оператора
На устройствах под управлением Android 9 или выше вы можете использовать приложение оператора для активации eSIM и загрузки профилей. Приложение оператора связи может загружать профили, напрямую вызывая downloadSubscription
или предоставляя код активации LPA.
Когда приложение оператора связи загружает профиль с помощью вызова downloadSubscription
, этот вызов обеспечивает возможность управления профилем приложением с помощью тега метаданных BF76
, который кодирует правила привилегий оператора связи для профиля. Если профиль не имеет тега BF76
или его тег BF76
не соответствует подписи приложения вызывающего оператора, загрузка отклоняется.
В разделе ниже описывается активация eSIM через приложение оператора связи с использованием кода активации.
Активация eSIM с помощью кода активации
При использовании кода активации для активации профиля eSIM LPA извлекает код активации из приложения оператора связи и загружает профиль. Этот поток может быть инициирован LPA, и LPA может управлять всем потоком пользовательского интерфейса, что означает, что пользовательский интерфейс приложения оператора не отображается. Этот подход обходит проверку тега BF76
, и сетевым операторам не нужно реализовывать весь процесс активации пользовательского интерфейса eSIM, включая загрузку профиля eSIM и обработку ошибок.
Определение службы подготовки eUICC оператора
LPA и приложение оператора взаимодействуют через два интерфейса AIDL : ICarrierEuiccProvisioningService
и IGetActivationCodeCallback
. Приложение-перевозчик должно реализовать интерфейс ICarrierEuiccProvisioningService
и предоставить его в своем объявлении манифеста . LPA должен привязаться к ICarrierEuiccProvisioningService
и реализовать IGetActivationCodeCallback
. Дополнительные сведения о реализации и предоставлении интерфейса AIDL см. в разделе Определение и интерфейс AIDL .
Чтобы определить интерфейсы AIDL, создайте следующие файлы AIDL как для LPA, так и для приложений-носителей.
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(); }
Пример реализации LPA
Чтобы выполнить привязку к реализации ICarrierEuiccProvisioningService
приложения-носителя, LPA должен скопировать оба ICarrierEuiccProvisioningService.aidl
и IGetActivationCodeCallback.aidl
в ваш проект и реализовать ServiceConnection
.
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
mCarrierProvisioningService = ICarrierEuiccProvisioningService.Stub.asInterface(iBinder);
}
После привязки к реализации ICarrierEuiccProvisioningService
приложения-носителя LPA вызывает либо getActivationCode
, либо getActivationCodeForEid
, чтобы получить код активации из приложения-носителя, передав реализацию класса-заглушки IGetActivationCodeCallback
.
Разница между getActivationCode
и getActivationCodeForEid
заключается в том, что getActivationCodeForEid
позволяет оператору предварительно привязать профиль к EID устройства до начала процесса загрузки.
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
}
}
Пример реализации для мобильного приложения
Чтобы LPA привязывался к приложению-носителю, приложение-носитель должно скопировать оба ICarrierEuiccProvisioningService.aidl
и IGetActivationCodeCallback.aidl
в ваш проект и объявить службу ICarrierEuiccProvisioningService
в файле AndroidManifest.xml
. Службе должно требоваться системное разрешение android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS
, чтобы гарантировать, что только LPA, приложение с системными привилегиями, может связываться с ней. Служба также должна включать фильтр намерений с действием 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>
Чтобы реализовать службу приложения-носителя AIDL, создайте службу, расширьте класс Stub
и реализуйте методы getActivationCode
и getActivationCodeForEid
. Затем LPA может вызвать любой метод для получения кода активации профиля. Приложение оператора должно ответить вызовом IGetActivationCodeCallback#onSuccess
с кодом активации, если код был успешно получен с сервера оператора. В случае неудачи приложение оператора связи должно ответить 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);
}
}
}
Запуск пользовательского интерфейса мобильного приложения в потоке активации LPA
На устройствах под управлением Android 11 и выше LPA может запускать пользовательский интерфейс приложения-оператора. Это полезно, поскольку приложению-оператору может потребоваться дополнительная информация от пользователя перед отправкой кода активации в LPA. Например, операторы связи могут потребовать, чтобы пользователи вошли в систему, чтобы активировать свои телефонные номера или выполнить другие услуги переноса.
Это процесс запуска пользовательского интерфейса приложения-носителя в LPA:
LPA запускает поток активации приложения-оператора, отправляя намерение
android.service.euicc.action.START_CARRIER_ACTIVATION
пакету приложения-оператора, содержащему действие. (Получатель приложения-носителя должен быть защищен в объявлении манифеста с помощьюandroid:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
, чтобы избежать получения намерений от приложений, не относящихся к 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);
Приложение оператора выполняет свою работу, используя собственный пользовательский интерфейс. Например, вход пользователя или отправка HTTP-запросов на серверную часть оператора.
Приложение-носитель отвечает на LPA, вызывая
setResult(int, Intent)
иfinish()
.- Если приложение-носитель отвечает
RESULT_OK
, LPA продолжает процесс активации. Если приложение-носитель определяет, что пользователь должен сканировать QR-код вместо того, чтобы позволять LPA привязывать службу приложения-носителя, приложение-носитель отвечает LPA, используяsetResult(int, Intent)
сRESULT_OK
и экземпляромIntent
, содержащим логический дополнительныйandroid.telephony.euicc.extra.USE_QR_SCANNER
имеет значениеtrue
. Затем LPA проверяет лишнее и запускает сканер QR вместо привязки реализацииICarrierEuiccProvisioningService
приложения-носителя. - Если приложение оператора дает сбой или отвечает
RESULT_CANCELED
(это код ответа по умолчанию), LPA отменяет процесс активации eSIM. - Если приложение-носитель отвечает чем-то другим, кроме
RESULT_OK
илиRESULT_CANCELED
, LPA рассматривает это как ошибку.
Из соображений безопасности LPA не должен напрямую принимать код активации, предоставленный в результате, чтобы гарантировать, что вызывающие абоненты, не являющиеся LPA, не смогут получить код активации из приложения оператора связи.
- Если приложение-носитель отвечает
Запуск процесса активации LPA в приложении оператора
Начиная с Android 11, приложения оператора связи могут использовать API-интерфейсы eUICC для запуска LUI для активации eSIM. Этот метод отображает пользовательский интерфейс процесса активации eSIM LPA для активации профиля eSIM. Затем LPA отправляет широковещательную рассылку, когда активация профиля eSIM завершается.
LPA должен объявить действие, включая фильтр намерений, с действием
android.service.euicc.action.START_EUICC_ACTIVATION
. Приоритет фильтра намерений должен быть установлен на ненулевое значение, если на устройстве присутствует несколько реализаций. Например:<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>
Приложение оператора выполняет свою работу, используя собственный пользовательский интерфейс. Например, вход пользователя или отправка HTTP-запросов на серверную часть оператора.
На этом этапе приложение оператора связи должно быть готово предоставить код активации через свою реализацию
ICarrierEuiccProvisioningService
. Приложение оператора запускает LPA, вызываяstartActivityForResult(Intent, int)
с действиемandroid.telephony.euicc.action.START_EUICC_ACTIVATION
. LPA также проверяет логический дополнительныйandroid.telephony.euicc.extra.USE_QR_SCANNER
. Если значение равноtrue
, LPA запускает сканер QR, чтобы пользователь мог отсканировать QR-код профиля.На стороне LPA LPA привязывается к реализации
ICarrierEuiccProvisioningService
приложения-перевозчика, чтобы получить код активации и загрузить соответствующий профиль. LPA отображает все необходимые элементы пользовательского интерфейса во время загрузки, например экран загрузки.Когда поток активации LPA завершен, LPA отвечает приложению-перевозчику кодом результата, который приложение-носитель обрабатывает в
onActivityResult(int, int, Intent)
.- Если LPA удается загрузить новый профиль eSIM, он отвечает
RESULT_OK
. - Если пользователь отменяет активацию профиля eSIM в LPA, он отвечает
RESULT_CANCELED
. - Если LPA отвечает чем-то другим, кроме
RESULT_OK
илиRESULT_CANCELED
, приложение-носитель рассматривает это как ошибку.
Из соображений безопасности LPA не принимает код активации непосредственно в предоставленном намерении, чтобы гарантировать, что вызывающие абоненты, не являющиеся LPA, не смогут получить код активации из приложения оператора связи.
- Если LPA удается загрузить новый профиль eSIM, он отвечает
Поддержка нескольких eSIM
Для устройств под управлением Android 10 или более поздней версии класс EuiccManager
поддерживает устройства с несколькими eSIM. Устройства с одним eSIM, которые обновляются до Android 10, не требуют каких-либо изменений в реализации LPA, поскольку платформа автоматически связывает экземпляр EuiccManager
с eUICC по умолчанию. eUICC по умолчанию определяется платформой для устройств с радио HAL версии 1.2 или выше и LPA для устройств с радио HAL версии ниже 1,2.
Требования
Для поддержки нескольких карт eSIM устройство должно иметь более одной карты eUICC, которая может быть либо встроенной картой eUICC, либо физическим слотом для SIM-карты, в который можно вставлять съемные карты eUICC.
Radio HAL версии 1.2 или выше требуется для поддержки нескольких eSIM. Рекомендуется Radio HAL версии 1.4 и RadioConfig HAL версии 1.2.
Реализация
Для поддержки нескольких eSIM (включая съемные eUICC или программируемые SIM-карты) LPA должен реализовать EuiccService
, который получает идентификатор слота, соответствующий идентификатору карты, предоставленному вызывающим абонентом.
non_removable_euicc_slots
, указанный в arrays.xml
, представляет собой массив целых чисел, представляющих идентификаторы слотов встроенных карт eUICC устройства. Вы должны указать этот ресурс, чтобы платформа могла определить, является ли вставленная карта eUICC съемной или нет.
Приложение Carrier для устройства с несколькими eSIM
При создании приложения-носителя для устройства с несколькими eSIM используйте метод createForCardId
в EuiccManager
, чтобы создать объект EuiccManager
, привязанный к данному идентификатору карты. Идентификатор карты — это целочисленное значение, которое однозначно идентифицирует UICC или eUICC на устройстве.
Чтобы получить идентификатор карты для eUICC устройства по умолчанию, используйте метод getCardIdForDefaultEuicc
в TelephonyManager
. Этот метод возвращает UNSUPPORTED_CARD_ID
, если версия радио HAL ниже 1.2, и возвращает UNINITIALIZED_CARD_ID
, если устройство не прочитало карту eUICC.
Вы также можете получить идентификаторы карт из getUiccCardsInfo
и getUiccSlotsInfo
(системный API) в TelephonyManager
и getCardId
в SubscriptionInfo
.
Когда создается экземпляр объекта EuiccManager
с определенным идентификатором карты, все операции направляются на карту eUICC с этим идентификатором карты. Если карта eUICC становится недоступной (например, когда она выключена или удалена) EuiccManager
больше не работает.
Вы можете использовать следующие примеры кода для создания мобильного приложения.
Пример 1: Получить активную подписку и создать экземпляр 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);
Пример 2. Перебор карт UICC и создание экземпляра EuiccManager
для съемной карты eUICC.
// On a device with a built-in eUICC and a removable eUICC, iterate through the UICC cards
// to instantiate an EuiccManager associated with a removable eUICC
TelephonyManager telMan = (TelephonyManager)
mContext.getSystemService(Context.TELEPHONY_SERVICE);
List<UiccCardInfo> infos = telMan.getUiccCardsInfo();
int removableCardId = -1; // valid cardIds are 0 or greater
for (UiccCardInfo info : infos) {
if (info.isRemovable()) {
removableCardId = info.getCardId();
break;
}
}
if (removableCardId != -1) {
EuiccManager euiccMan = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE)
.createForCardId(removableCardId);
}
Проверка
AOSP не поставляется с реализацией LPA, и не ожидается, что LPA будет доступен во всех сборках Android (не каждый телефон поддерживает eSIM). По этой причине не существует сквозных тестов CTS. Однако в AOSP доступны базовые тестовые примеры, чтобы убедиться, что открытые API-интерфейсы eUICC действительны в сборках Android.
Вы должны убедиться, что сборки проходят следующие тестовые случаи CTS (для общедоступных API): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts .
Операторы связи, внедряющие приложение оператора связи, должны пройти обычные внутренние циклы проверки качества, чтобы убедиться, что все реализованные функции работают должным образом. Как минимум, приложение оператора связи должно иметь возможность перечислить все профили подписки, принадлежащие одному и тому же оператору, загрузить и установить профиль, активировать службу в профиле, переключаться между профилями и удалять профили.
Если вы делаете свой собственный LPA, вы должны пройти гораздо более тщательное тестирование. Вам следует сотрудничать с поставщиком модема, чипом eUICC или поставщиком ОС eSIM, поставщиками SM-DP+ и операторами связи для решения проблем и обеспечения совместимости вашего LPA в архитектуре RSP. Большое количество ручного тестирования неизбежно. Для наилучшего покрытия тестами вы должны следовать плану тестирования GSMA SGP.23 RSP .