Встроенная SIM-карта (eSIM или eUICC) — это новейшая технология, позволяющая мобильным пользователям загружать и активировать профиль оператора, не имея физической SIM-карты.
Это глобальная спецификация, разработанная GSMA, которая обеспечивает удаленную инициализацию SIM-карт любого мобильного устройства. Начиная с Android 9, платформа Android предоставляет стандартные API для доступа к eSIM и управления профилями подписки.
ЭтиAPI-интерфейсы eUICC позволяют сторонним разработчикам создавать собственные приложения-носители и локальные помощники профилей (LPA) на устройствах Android с поддержкой eSIM.
LPA — это автономное системное приложение, которое должно быть включено в образ сборки Android. Управление профилями в eSIM обычно осуществляется LPA, поскольку он служит мостом между SM-DP + (удаленная служба, которая подготавливает, хранит и доставляет пакеты профилей на устройства) и чипом eUICC.
LPA APK может дополнительно включать компонент пользовательского интерфейса, называемый LPA UI или LUI, чтобы предоставить конечному пользователю центральное место для управления всеми встроенными профилями подписки. Платформа Android автоматически обнаруживает и подключается к наилучшему доступному LPA и направляет все операции eUICC через экземпляр LPA.
Рисунок 1. Упрощенная архитектура удаленного предоставления SIM-карт (RSP)
Операторы мобильной сети , заинтересованные в создании приложения — носителя следует обратить внимание на API , в EuiccManager , которая обеспечивает операции управления профилем высокого уровня , такие какdownloadSubscription()
, switchToSubscription()
и deleteSubscription()
.
Если вы являетесь изготовителем устройства, заинтересованным в создании собственного системного приложения LPA, вы должны расширить EuiccService для платформы Android, чтобы подключаться к вашим службам LPA. Кроме того, вы должны использовать API в EuiccCardManager , который обеспечивает функции ES10x на основе GSMA Remote SIM Provisioning (RSP) v2.0. Эти функции используются для выдачи команд на чип eUICC, такие как prepareDownload()
, loadBoundProfilePackage()
, retrieveNotificationList()
, и resetMemory()
.
Для работы API в EuiccManager требуется правильно реализованное приложение LPA, а вызывающим дляAPI EuiccCardManager должен быть LPA. Это обеспечивается платформой Android.
Создание приложения для оператора
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 as EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, что позволяет приложению-поставщику отслеживать для целей регистрации / отладки. PendingIntent
Должно быть BroadcastReceiver
.
Чтобы загрузить данные DownloadableSubscription
(созданные из кода активации или 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,
/* 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(), /* 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,
/* 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(), /* requestCode */, intent,
PendingIntent.FLAG_UPDATE_CURRENT);
mgr.switchToSubscription(1 /* subscriptionId */, callbackIntent);
Полный список EuiccManager
API и примеры кода см. В разделе 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 input carrier confirmation code. */
public static final String ACTION_RESOLVE_CONFIRMATION_CODE =
"android.service.euicc.action.RESOLVE_CONFIRMATION_CODE";
Привилегии перевозчика
Если вы являетесь оператором, разрабатывающим собственное приложение для операторов, которое запрашивает EuiccManager
загрузку профилей на устройство, ваш профиль должен включать в метаданные правила привилегий операторов, соответствующие вашему приложению. Это связано с тем, что в eUICC устройства могут сосуществовать профили подписки, принадлежащие разным носителям, и каждому приложению-носителю должен быть разрешен только доступ к профилям, принадлежащим этому носителю. Например, оператор связи А не должен иметь возможность загружать, включать или отключать профиль, принадлежащий оператору Б.
Чтобы гарантировать, что профиль доступен только его владельцу, Android использует механизм предоставления специальных привилегий приложению владельца профиля (то есть приложению-носителю). Платформа Android загружает сертификаты, хранящиеся в файле правил доступа (ARF) профиля, и предоставляет приложениям, подписанным этими сертификатами, разрешение на вызовы EuiccManager
API. Процесс высокого уровня описан ниже:
- Оператор подписывает приложение-носитель APK; apksigner инструмент прикрепляет сертификат открытого ключа в АПК.
- Оператор / SM-DP + подготавливает профиль и его метаданные, которые включают в себя ARF, который содержит:
- Подпись (SHA-1 или SHA-256) сертификата открытого ключа приложения-носителя (обязательно)
- Название пакета приложения-носителя (необязательно)
- Приложение Carrier пытается выполнить операцию eUICC через
EuiccManager
API. - Платформа Android проверяет, что хэш SHA-1 или SHA-256 сертификата приложения вызывающего абонента совпадает с подписью сертификата, полученного из ARF целевого профиля. Если имя пакета приложения-носителя включено в ARF, оно также должно совпадать с именем пакета приложения вызывающего абонента.
- После проверки подписи и имени пакета (если оно включено) привилегия оператора предоставляется приложению вызывающей стороны через целевой профиль.
Поскольку метаданные профиля могут быть доступны за пределами самого профиля (чтобы LPA мог получать метаданные профиля из SM-DP + до загрузки профиля или из ISD-R, когда профиль отключен), он должен содержать те же правила привилегий несущей. как в профиле.
ОС eUICC и SM-DP + должны поддерживать собственный тег BF76 в метаданных профиля. Содержимое тега должно соответствовать тем же правилам привилегий оператора, что и ARA (апплет правила доступа), определенный в 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] BIT STRING (SIZE(8)) -- Tag DB
}
}
Подробнее о подписи приложения см. В разделе « Подписать приложение» . Подробнее о привилегиях оператора см. В разделе « Права оператора UICC» .
Создание приложения LPA
Вы можете реализовать свой собственный LPA, который должен быть подключен к API Android Euicc. В следующих разделах дается краткий обзор создания приложения LPA и его интеграции с системой Android.
Требования к оборудованию / модему
LPA и операционная система eSIM на микросхеме eUICC должны поддерживать как минимум GSMA RSP (Remote SIM Provisioning) v2.0 или v2.2. Также следует запланировать использование серверов SM-DP + и SM-DS, которые имеют соответствующую версию RSP. Для получения подробной архитектуры RSP см. Спецификацию архитектуры RSP GSMA.21 SGP.21 .
Кроме того, для интеграции с API eUICC в Android 9 модем устройства должен отправлять возможности терминала с кодированной поддержкой eUICC (локальное управление профилем и загрузка профиля). Также необходимо реализовать следующие API:
- IRadio HAL v1.1: setSimPower
- IRadio HAL v1.2: getIccCardStatus
- IRadioConfig HAL v1.0: getSimSlotsStatus
Модем должен распознавать eSIM с включенным профилем загрузки по умолчанию в качестве действующей SIM-карты и поддерживать питание SIM-карты включенным.
Полный список требований к модему см. В разделе Требования к модему для поддержки 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 используют Euicc API
API для работы с профилем EuiccCardManager
требуют, чтобы вызывающая сторона была LPA. Это обеспечивается платформой Android. Это означает, что вызывающая сторона должна расширить EuiccService
и быть объявлена в вашем файле манифеста, как описано в предыдущих разделах.
Подобно тому EuiccManager
, чтобы использовать EuiccCardManager
API, ваш 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. При использовании EuiccCardManager
API вызывающая сторона (LPA) должна предоставить Executor
сквозную функцию, через которую вызывается обратный вызов. Это Executor
может выполняться в одном потоке или в пуле потоков по вашему выбору.
Большинство EuiccCardManager
API имеют одинаковый шаблон использования. Например, чтобы загрузить пакет привязанного профиля в 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);
Проверка
AOSP не поставляется с реализацией LPA, и ожидается, что LPA не будет доступен во всех сборках Android (не каждый телефон поддерживает eSIM). По этой причине нет сквозных тестовых случаев CTS. Тем не менее, в AOSP доступны базовые тестовые случаи, чтобы убедиться, что открытые API eUICC действительны в сборках Android.
Вы должны убедиться, что сборки проходят следующие тестовые сценарии CTS (для общедоступных API):
https://android.googlesource.com/platform/cts/+/master/tests/tests/telephony/src/android/telephony/
Операторы, внедряющие приложение для операторов связи, должны пройти свои обычные внутренние циклы обеспечения качества, чтобы убедиться, что все реализованные функции работают должным образом. Как минимум, приложение оператора связи должно иметь возможность перечислять все профили подписки, принадлежащие одному и тому же оператору, загружать и устанавливать профиль, активировать службу в профиле, переключаться между профилями и удалять профили.
Если вы делаете свой собственный LPA, вы должны пройти гораздо более тщательное тестирование. Вам следует обратиться к поставщику модема, поставщику чипа eUICC или ОС eSIM, поставщикам SM-DP + и операторам для решения проблем и обеспечения совместимости вашего LPA в архитектуре RSP. Хорошее количество ручного тестирования неизбежно. Для лучшего покрытия тестами вы должны следовать плану тестирования GSSP SGP.23 RSP .