Triển khai eSIM

Công nghệ SIM được nhúng (eSIM hay eUICC) cho phép người dùng di động tải hồ sơ nhà mạng xuống và kích hoạt dịch vụ của nhà mạng mà không cần phải thẻ SIM thực. Đây là một bộ thông số kỹ thuật toàn cầu dựa trên GSMA, cho phép cấp phép SIM từ xa (RSP) của bất kỳ thiết bị di động nào. Bắt đầu với Android 9, khung Android cung cấp các API tiêu chuẩn để truy cập vào eSIM và quản lý hồ sơ gói thuê bao trên eSIM đó. Các eUICC này API cho phép các bên thứ ba phát triển ứng dụng của nhà mạng và hồ sơ cục bộ của riêng họ trợ lý ảo (LPA) trên thiết bị Android hỗ trợ eSIM.

LPA là một ứng dụng hệ thống độc lập phải được đưa vào Hình ảnh bản dựng Android. Việc quản lý các hồ sơ trên eSIM thường được thực hiện bằng LPA, vì nó đóng vai trò là cầu nối giữa SM-DP+ (dịch vụ từ xa chuẩn bị, lưu trữ và phân phối các gói hồ sơ đến thiết bị) và chip eUICC. APK LPA có thể tùy chọn bao gồm một thành phần giao diện người dùng, được gọi là LPA UI hoặc LUI, để cung cấp một vị trí trung tâm để người dùng cuối quản lý tất cả các gói thuê bao được nhúng hồ sơ. Khung Android tự động phát hiện và kết nối với LPA có sẵn và định tuyến tất cả hoạt động eUICC thông qua một phiên bản LPA.

Cấu trúc Cấp phép SIM từ xa đơn giản (RSP)

Hình 1. Kiến trúc RSP được đơn giản hoá

Các nhà mạng di động muốn tạo ứng dụng của nhà mạng nên xem xét các API trong EuiccManager! cung cấp các hoạt động quản lý hồ sơ cấp cao như downloadSubscription(), switchToSubscription()deleteSubscription().

Nếu là nhà sản xuất thiết bị gốc (OEM) muốn tạo ứng dụng hệ thống LPA của riêng mình, thì bạn phải mở rộng EuiccService cho khung Android kết nối với các dịch vụ LPA của bạn. Ngoài ra, bạn nên sử dụng các API trong EuiccCardManager! Cung cấp các chức năng ES10x dựa trên GSMA RSP v2.0. Các hàm này dùng để phát lệnh cho chip eUICC, chẳng hạn như prepareDownload(), loadBoundProfilePackage(), retrieveNotificationList()resetMemory().

Các API trong EuiccManager đòi hỏi một ứng dụng LPA được triển khai đúng cách để hoạt động và phương thức gọi của EuiccCardManager Các API phải là một LPA. Yêu cầu này do khung Android thực thi.

Các thiết bị chạy Android 10 trở lên có thể hỗ trợ thiết bị có nhiều eSIM. Để biết thêm thông tin, hãy xem Hỗ trợ nhiều eSIM.

Tạo ứng dụng của nhà mạng

API eUICC trong Android 9 có thể giúp nhà cung cấp dịch vụ mạng di động để tạo ứng dụng mang thương hiệu nhà mạng nhằm quản lý hồ sơ. Điều này bao gồm việc tải xuống và xoá hồ sơ của gói thuê bao thuộc sở hữu của nhà mạng cũng như chuyển sang hồ sơ thuộc sở hữu của nhà mạng.

Trình quản lý Euicc

EuiccManager là điểm truy cập chính để các ứng dụng tương tác với LPA. Điều này bao gồm cả những ứng dụng của nhà mạng tải xuống, xoá và chuyển sang gói thuê bao do nhà mạng sở hữu. Trong đó cũng có ứng dụng hệ thống LUI, cung cấp một vị trí/giao diện người dùng trung tâm để quản lý tất cả các gói thuê bao được nhúng, và có thể là một ứng dụng riêng biệt với ứng dụng cung cấp EuiccService.

Để sử dụng API công khai, trước tiên, ứng dụng của nhà mạng phải có được thực thể của EuiccManager đến Context#getSystemService:

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

Bạn nên kiểm tra xem eSIM có được hỗ trợ trên thiết bị hay không trước khi thực hiện bất kỳ thao tác nào Hoạt động trên eSIM. EuiccManager#isEnabled() thường trả về true nếu Tính năng android.hardware.telephony.euicc được định nghĩa và gói LPA được xác định hiện tại.

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

Cách nhận thông tin về phần cứng eUICC và phiên bản hệ điều hành eSIM:

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

Nhiều API, chẳng hạn như downloadSubscription()switchToSubscription(), sử dụng PendingIntent vì có thể mất vài giây hoặc thậm chí vài phút để hoàn tất. PendingIntent được gửi cùng với một mã kết quả trong EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_ không gian, cung cấp mã lỗi do khung xác định, cũng như mã kết quả chi tiết tuỳ ý được truyền từ LPA dưới dạng EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, cho phép ứng dụng của nhà mạng để theo dõi cho mục đích ghi nhật ký/gỡ lỗi. PendingIntent hàm callback phải là BroadcastReceiver.

Để tải xuống một gói thuê bao có thể tải xuống nhất định (được tạo từ một mã kích hoạt hoặc mã QR):

// Register receiver.
static final String ACTION_DOWNLOAD_SUBSCRIPTION = "download_subscription";
static final String LPA_DECLARED_PERMISSION
    = "com.your.company.lpa.permission.BROADCAST";
BroadcastReceiver receiver =
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                if (!action.equals(intent.getAction())) {
                    return;
                }
                resultCode = getResultCode();
                detailedCode = intent.getIntExtra(
                    EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE,
                    0 /* defaultValue*/);

                // If the result code is a resolvable error, call startResolutionActivity
                if (resultCode == EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR) {
                    PendingIntent callbackIntent = PendingIntent.getBroadcast(
                        getContext(), 0 /* requestCode */, intent,
                        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
                    mgr.startResolutionActivity(
                        activity,
                        0 /* requestCode */,
                        intent,
                        callbackIntent);
                }

                resultIntent = intent;
            }
        };
context.registerReceiver(receiver,
        new IntentFilter(ACTION_DOWNLOAD_SUBSCRIPTION),
        LPA_DECLARED_PERMISSION /* broadcastPermission*/,
        null /* handler */);

// Download subscription asynchronously.
DownloadableSubscription sub = DownloadableSubscription
        .forActivationCode(code /* encodedActivationCode*/);
Intent intent = new Intent(action).setPackage(context.getPackageName());
PendingIntent callbackIntent = PendingIntent.getBroadcast(
        getContext(), 0 /* requestCode */, intent,
        PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
mgr.downloadSubscription(sub, true /* switchAfterDownload */,
        callbackIntent);

Định nghĩa và sử dụng quyền trong AndroidManifest.xml:

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

Cách chuyển sang gói thuê bao được cung cấp mã nhận dạng gói thuê bao:

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

Để xem danh sách đầy đủ các API EuiccManager và ví dụ về mã, hãy xem Các API eUICC.

Lỗi có thể giải quyết

Có một số trường hợp hệ thống không thể hoàn tất thao tác eSIM nhưng người dùng có thể khắc phục lỗi. Ví dụ: downloadSubscription có thể không thành công nếu siêu dữ liệu của hồ sơ cho biết rằng có mã xác nhận của nhà mạng là trường bắt buộc. Hoặc switchToSubscription có thể không thành công nếu ứng dụng của nhà mạng có nhà mạng đặc quyền đối với hồ sơ đích (tức là nhà cung cấp dịch vụ sở hữu hồ sơ) nhưng không có đặc quyền của nhà mạng đối với hồ sơ hiện được bật và do đó cần có sự đồng ý của người dùng.

Đối với những trường hợp này, lệnh gọi lại của phương thức gọi được gọi bằng EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR. Lệnh gọi lại Intent chứa các phần bổ sung nội bộ mà khi phương thức gọi truyền nó đến EuiccManager#startResolutionActivity, có thể được yêu cầu thông qua LUI. Sử dụng mã xác nhận cho một lần nữa, EuiccManager#startResolutionActivity kích hoạt màn hình LUI cho phép người dùng nhập mã xác nhận; sau khi nhập mã, hoạt động tải xuống sẽ được tiếp tục. Phương pháp này cung cấp cho ứng dụng của nhà mạng toàn quyền kiểm soát thời điểm giao diện người dùng được hiển thị, nhưng sẽ cho phép LPA/LUI, một phương thức có thể mở rộng để thêm các thao tác xử lý mới đối với những sự cố trong tương lai mà không cần ứng dụng khách thay đổi.

Android 9 xác định các lỗi có thể giải quyết này trong EuiccService! mà LUI sẽ xử lý:

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

Đặc quyền của nhà mạng

Nếu bạn là một nhà mạng đang phát triển ứng dụng của riêng nhà mạng để gọi EuiccManager để tải hồ sơ xuống một thiết bị, hồ sơ của bạn phải bao gồm nhà mạng tương ứng với ứng dụng của nhà mạng trong siêu dữ liệu. Đây là vì hồ sơ gói thuê bao của các nhà mạng khác nhau có thể cùng tồn tại ở eUICC của một thiết bị và mỗi ứng dụng của nhà mạng chỉ được phép truy cập vào hồ sơ thuộc sở hữu của nhà mạng đó. Ví dụ: nhà mạng A không thể tải xuống, bật hoặc vô hiệu hoá hồ sơ do nhà mạng B sở hữu.

Để đảm bảo chỉ chủ sở hữu mới có thể truy cập vào hồ sơ, Android sử dụng một cơ chế để cấp đặc quyền cho ứng dụng của chủ sở hữu trang doanh nghiệp (tức là ứng dụng của nhà mạng). Chiến lược phát hành đĩa đơn Nền tảng Android tải các chứng chỉ được lưu trữ trong tệp quy tắc truy cập của hồ sơ (ARF) và cấp quyền thực hiện cuộc gọi cho các ứng dụng được ký bởi những chứng chỉ này vào các API EuiccManager. Dưới đây là quy trình cấp cao:

  1. Nhà cung cấp ký APK ứng dụng của nhà mạng; thời gian apksigner sẽ đính kèm chứng chỉ khoá công khai vào APK.
  2. Nhà cung cấp dịch vụ/SM-DP+ chuẩn bị một hồ sơ và siêu dữ liệu của hồ sơ đó, bao gồm cả ARF có chứa:

    1. Chữ ký (SHA-1 hoặc SHA-256) trong chứng chỉ khoá công khai của ứng dụng của nhà mạng (bắt buộc)
    2. Tên gói của ứng dụng của nhà mạng (rất nên dùng)
  3. Ứng dụng của nhà mạng cố gắng thực hiện một thao tác eUICC bằng API EuiccManager.

  4. Nền tảng Android xác minh hàm băm SHA-1 hoặc SHA-256 của ứng dụng gọi khớp với chữ ký của chứng chỉ thu được từ ARF của hồ sơ mục tiêu. Nếu tên gói của ứng dụng của nhà mạng được đưa vào ARF thì mã này cũng phải khớp với tên gói của ứng dụng gọi.

  5. Sau khi chữ ký và tên gói (nếu có) được xác minh, đặc quyền của nhà mạng sẽ được cấp cho ứng dụng gọi qua hồ sơ đích.

Vì siêu dữ liệu của hồ sơ có thể có sẵn bên ngoài chính hồ sơ (do đó LPA có thể truy xuất siêu dữ liệu hồ sơ từ SM-DP+ trước khi hồ sơ được được tải xuống hoặc từ ISD-R khi cấu hình bị vô hiệu hoá), tệp sẽ chứa quy tắc đặc quyền của nhà mạng như trong hồ sơ.

Hệ điều hành eUICC và SM-DP+ phải hỗ trợ một thẻ độc quyền BF76 trong hồ sơ siêu dữ liệu. Nội dung thẻ phải giống với các quy tắc đặc quyền của nhà cung cấp dịch vụ như được trả về theo chương trình phụ trợ quy tắc truy cập (ARA) được xác định trong Đặc quyền của nhà mạng 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
    }
}

Để biết thêm thông tin chi tiết về tính năng ký ứng dụng, hãy xem Ký ứng dụng. Để biết chi tiết về đặc quyền của nhà mạng, hãy xem Đặc quyền của nhà mạng UICC.

Tạo ứng dụng trợ lý hồ sơ cục bộ

Nhà sản xuất thiết bị có thể triển khai trợ lý hồ sơ cục bộ (LPA) của riêng họ, Nội dung phải hấp dẫn với API Euicc của Android. Các phần sau đây sẽ cung cấp tổng quan ngắn gọn về tạo một ứng dụng LPA và tích hợp ứng dụng này với hệ thống Android.

Yêu cầu về phần cứng/modem

LPA và eSIM OS trên chip eUICC phải hỗ trợ ít nhất GSMA RSP (Điều khiển từ xa Cấp phép SIM) v2.0 hoặc v2.2. Bạn cũng nên lên kế hoạch sử dụng SM-DP+ và SM-DS máy chủ có phiên bản RSP phù hợp. Để biết cấu trúc RSP chi tiết, hãy xem Thông số kỹ thuật kiến trúc GSMA SGP.21 RSP.

Ngoài ra, để tích hợp với các API eUICC trong Android 9, modem thiết bị phải gửi các tính năng của thiết bị đầu cuối với sự hỗ trợ cho các chức năng eUICC được mã hoá (quản lý hồ sơ cục bộ và tải hồ sơ xuống). Nền tảng này cũng cần triển khai các phương thức sau:

  • IRadio HAL phiên bản 1.1: setSimPower
  • IRadio HAL phiên bản 1.2: getIccCardStatus

  • IRadioConfig HAL phiên bản 1.0: getSimSlotsStatus

  • IRadioConfig AIDL phiên bản 1.0: getAllowedCarriers

    LPA của Google cần biết trạng thái khoá của nhà mạng để chỉ có thể cho phép tải hoặc chuyển eSIM xuống đối với nhà mạng được cho phép. Nếu không, người dùng có thể sẽ tải xuống và chuyển SIM, sau đó nhận ra rằng thiết bị bị khoá với một nhà mạng khác.

    • Nhà cung cấp hoặc OEM phải triển khai API IRadioSim.getAllowedCarriers().

    • RIL / Modem của nhà cung cấp sẽ điền trạng thái khoá và providerId của nhà mạng nơi thiết bị bị khoá như một phần của API IRadioSimResponse.getAllowedCarriersResponse().

Modem phải nhận ra eSIM đã bật hồ sơ khởi động mặc định là SIM hợp lệ và luôn bật nguồn SIM.

Đối với các thiết bị chạy Android 10, eUICC không thể tháo rời phải xác định mảng ID vị trí. Ví dụ: hãy xem 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>

Để có danh sách đầy đủ các yêu cầu đối với modem, hãy xem Các yêu cầu về Modem để hỗ trợ eSIM.

Dịch vụ Euicc

Một LPA bao gồm hai thành phần riêng biệt (có thể cả hai được triển khai trong cùng một LPA APK): phần phụ trợ LPA và LPA UI hoặc LUI.

Để triển khai phần phụ trợ LPA, bạn phải mở rộng EuiccService rồi khai báo dịch vụ này trong tệp kê khai. Dịch vụ phải yêu cầu android.permission.BIND_EUICC_SERVICE quyền hệ thống để đảm bảo rằng chỉ mà hệ thống có thể liên kết với tệp đó. Dịch vụ này cũng phải bao gồm một bộ lọc ý định có thao tác android.service.euicc.EuiccService. Mức độ ưu tiên của ý định nên đặt bộ lọc thành một giá trị khác 0 trong trường hợp có nhiều lần triển khai có trên thiết bị. Ví dụ:

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

Trong nội bộ, khung Android xác định LPA đang hoạt động và tương tác với cần thiết để hỗ trợ các API eUICC của Android. PackageManager được truy vấn tất cả ứng dụng có quyền android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS, Mã này chỉ định một dịch vụ cho thao tác android.service.euicc.EuiccService. Dịch vụ có mức độ ưu tiên cao nhất sẽ được chọn. Nếu không tìm thấy dịch vụ nào, LPA chế độ hỗ trợ đã bị tắt.

Để triển khai LUI, bạn phải cung cấp hoạt động cho những thao tác sau:

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

Giống như dịch vụ này, mỗi hoạt động phải yêu cầu Quyền hệ thống android.permission.BIND_EUICC_SERVICE. Mỗi nguồn cấp dữ liệu phải có một bộ lọc ý định bằng hành động thích hợp, android.service.euicc.category.EUICC_UI và một mức độ ưu tiên khác 0. Logic tương tự được dùng để chọn phương thức triển khai cho các hoạt động này làm với việc chọn phương thức triển khai EuiccService. Ví dụ:

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

Điều này có nghĩa là giao diện người dùng triển khai những màn hình này có thể đến từ một APK của một dịch vụ triển khai EuiccService. Liệu nên có một hay nhiều tệp APK (ví dụ: một tệp APK triển khai EuiccService và một thuộc tính cung cấp các hoạt động LUI) là một lựa chọn thiết kế.

EuiccCardManager

EuiccCardManager là giao diện để giao tiếp với chip eSIM. Nó cung cấp các chức năng ES10 (như được mô tả trong thông số kỹ thuật GSMA RSP) và xử lý các lệnh yêu cầu/phản hồi APDU cấp thấp cũng như phân tích cú pháp ASN.1. EuiccCardManager là một API hệ thống và chỉ có đặc quyền hệ thống mới có thể gọi của chúng tôi.

API của nhà mạng, LPA và Euicc

Hình 2. Cả ứng dụng của nhà mạng và LPA đều sử dụng API Euicc

Các API thao tác trên hồ sơ thông qua EuiccCardManager yêu cầu phương thức gọi phải một LPA. Yêu cầu này do khung Android thực thi. Điều này có nghĩa là phương thức gọi phải mở rộng EuiccService và được khai báo trong tệp kê khai, như mô tả trong các phần trước.

Tương tự như EuiccManager, để sử dụng các API EuiccCardManager, LPA của bạn phải trước tiên, hãy lấy thực thể của EuiccCardManager thông qua Context#getSystemService:

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

Sau đó, để tải tất cả các hồ sơ trên eUICC, hãy làm như sau:

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

Trong nội bộ, EuiccCardManager liên kết với EuiccCardController (chạy trong điện thoại) thông qua giao diện AIDL và từng phương thức EuiccCardManager nhận lệnh gọi lại từ quy trình điện thoại thông qua một AIDL riêng, khác . Khi sử dụng các API EuiccCardManager, phương thức gọi (LPA) phải cung cấp Executor qua đối tượng mà lệnh gọi lại được gọi ra. Đối tượng Executor này có thể chạy trên một chuỗi hoặc trên một nhóm chuỗi mà bạn chọn.

Hầu hết API EuiccCardManager đều có cùng một kiểu sử dụng. Ví dụ: để tải một liên kết gói hồ sơ trên eUICC:

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

Cách chuyển sang một hồ sơ khác có ICCID cho trước:

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

Cách lấy địa chỉ SM-DP+ mặc định từ chip eUICC:

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

Cách truy xuất danh sách thông báo của các sự kiện thông báo nhất định:

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

Kích hoạt hồ sơ eSIM thông qua một ứng dụng của nhà mạng

Trên thiết bị chạy Android 9 trở lên, bạn có thể dùng ứng dụng của nhà mạng để kích hoạt eSIM và tải hồ sơ xuống. Ứng dụng của nhà mạng có thể tải hồ sơ xuống bằng cách đang gọi downloadSubscription trực tiếp hoặc bằng cách cung cấp mã kích hoạt cho LPA.

Khi một ứng dụng của nhà mạng tải một hồ sơ xuống bằng cách gọi downloadSubscription! lệnh gọi thực thi việc ứng dụng có thể quản lý hồ sơ thông qua BF76 thẻ siêu dữ liệu để mã hoá các quy tắc đặc quyền của nhà mạng cho hồ sơ. Nếu một hồ sơ không có thẻ BF76 hoặc nếu thẻ BF76 của hồ sơ đó không có khớp với chữ ký của ứng dụng gọi của nhà mạng, thì nội dung tải xuống sẽ bị từ chối.

Phần dưới đây mô tả việc kích hoạt eSIM thông qua một ứng dụng của nhà mạng bằng mã kích hoạt.

Kích hoạt eSIM bằng mã kích hoạt

Khi sử dụng mã kích hoạt để kích hoạt hồ sơ eSIM, LPA sẽ tìm nạp mã kích hoạt từ ứng dụng của nhà mạng rồi tải hồ sơ xuống. Quy trình này có thể do LPA bắt đầu và LPA có thể kiểm soát toàn bộ luồng giao diện người dùng, nghĩa là không có giao diện người dùng ứng dụng nào của nhà mạng hiển thị. Phương pháp này bỏ qua bước kiểm tra thẻ BF76, nên nhà vận hành mạng sẽ không cần triển khai toàn bộ quy trình giao diện người dùng kích hoạt eSIM, bao gồm cả việc tải xuống Hồ sơ eSIM và cách xử lý lỗi.

Xác định dịch vụ cung cấp eUICC của nhà mạng

LPA và ứng dụng của nhà mạng giao tiếp qua hai AIDL giao diện: ICarrierEuiccProvisioningServiceIGetActivationCodeCallback. Hãng vận chuyển ứng dụng phải triển khai giao diện ICarrierEuiccProvisioningService và hiển thị dữ liệu đó trong khai báo tệp kê khai. LPA phải liên kết với ICarrierEuiccProvisioningService và triển khai IGetActivationCodeCallback. Để biết thêm thông tin về cách triển khai và hiển thị giao diện AIDL, hãy xem phần Xác định và giao diện AIDL.

Để xác định các giao diện AIDL, hãy tạo các tệp AIDL sau cho cả ứng dụng của nhà mạng và 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();
    }
    

Ví dụ về cách triển khai LPA

Để liên kết với hoạt động triển khai ICarrierEuiccProvisioningService của ứng dụng nhà mạng, LPA phải sao chép cả ICarrierEuiccProvisioningService.aidlIGetActivationCodeCallback.aidl cho dự án của bạn và triển khai ServiceConnection.

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

Sau khi liên kết với ICarrierEuiccProvisioningService của ứng dụng mạng LPA sẽ gọi getActivationCode hoặc getActivationCodeForEid để nhận mã kích hoạt từ ứng dụng của nhà mạng bằng cách truyền phương thức triển khai lớp mã giả lập IGetActivationCodeCallback.

Sự khác biệt giữa getActivationCodegetActivationCodeForEidgetActivationCodeForEid cho phép nhà mạng liên kết trước một hồ sơ với EID (mã định danh dành cho eSIM) trước khi quá trình tải xuống bắt đầu.

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

Ví dụ về cách triển khai cho ứng dụng của nhà mạng

Để LPA liên kết với ứng dụng của nhà mạng, ứng dụng của nhà mạng phải sao chép cả hai ICarrierEuiccProvisioningService.aidlIGetActivationCodeCallback.aidl đến dự án của bạn và khai báo dịch vụ ICarrierEuiccProvisioningService trong AndroidManifest.xml. Dịch vụ phải yêu cầu Quyền hệ thống của android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS để đảm bảo mà chỉ LPA (một ứng dụng đặc quyền của hệ thống) mới có thể liên kết với ứng dụng đó. Dịch vụ phải Ngoài ra, bạn cũng có thể thêm bộ lọc ý định với android.service.euicc.action.BIND_CARRIER_PROVISIONING_SERVICE hành động.

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

Để triển khai dịch vụ ứng dụng của nhà mạng AIDL, hãy tạo một dịch vụ, mở rộng Stub và triển khai getActivationCodegetActivationCodeForEid . Sau đó, LPA có thể gọi một trong hai phương thức để tìm nạp thông tin kích hoạt hồ sơ . Ứng dụng của nhà mạng sẽ phản hồi bằng cách gọi IGetActivationCodeCallback#onSuccess kèm theo mã kích hoạt nếu mã đó đã được tìm nạp từ máy chủ của nhà mạng. Nếu không thành công, ứng dụng của nhà mạng phải phản hồi bằng 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);
              }
          }
    }
    

Khởi động giao diện người dùng của ứng dụng của nhà mạng trong quy trình kích hoạt LPA

Trên các thiết bị chạy Android 11 trở lên, LPA có thể khởi động giao diện người dùng của một ứng dụng của nhà mạng. Điều này rất hữu ích vì ứng dụng của nhà mạng có thể yêu cầu thêm thông tin từ người dùng trước khi cung cấp mã kích hoạt cho LPA. Ví dụ: các nhà mạng có thể yêu cầu người dùng đăng nhập để kích hoạt số điện thoại của họ hoặc thực hiện quá trình chuyển khác luôn miễn phí.

Đây là quy trình bắt đầu giao diện người dùng của một ứng dụng của nhà mạng trong LPA:

  1. LPA khởi chạy quy trình kích hoạt của ứng dụng của nhà mạng bằng cách gửi Ý định android.service.euicc.action.START_CARRIER_ACTIVATION đối với gói ứng dụng của nhà mạng chứa hành động. (Người nhận ứng dụng của nhà mạng phải được bảo vệ trong phần khai báo tệp kê khai bằng android:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS" thành tránh nhận ý định từ các ứng dụng không phải LPA.)

    String packageName = // The carrier app's package name
    
    Intent carrierAppIntent =
        new Intent(“android.service.euicc.action.START_CARRIER_ACTIVATION”)
            .setPackage(packageName);
    
    ResolveInfo activity =
        context.getPackageManager().resolveActivity(carrierAppIntent, 0);
    
    carrierAppIntent
        .setClassName(activity.activityInfo.packageName, activity.activityInfo.name);
    
    startActivityForResult(carrierAppIntent, requestCode);
    
  2. Ứng dụng của nhà mạng thực hiện công việc bằng cách sử dụng giao diện người dùng riêng. Ví dụ: ghi nhật ký trong người dùng hoặc gửi yêu cầu HTTP đến máy chủ phụ trợ của nhà mạng.

  3. Ứng dụng của nhà mạng phản hồi LPA bằng cách gọi setResult(int, Intent)finish().

    1. Nếu ứng dụng của nhà mạng phản hồi bằng RESULT_OK, thì LPA tiếp tục quy trình kích hoạt. Nếu ứng dụng của nhà mạng xác định rằng người dùng nên quét mã QR thay vì để LPA ràng buộc nhà mạng dịch vụ của ứng dụng, thì ứng dụng của nhà mạng sẽ phản hồi LPA bằng cách sử dụng setResult(int, Intent) cho RESULT_OK và một thực thể Intent chứa boolean bổ sung Đã đặt android.telephony.euicc.extra.USE_QR_SCANNER thành true. LPA sau đó kiểm tra phần bổ sung và chạy trình quét QR thay vì liên kết cách triển khai ICarrierEuiccProvisioningService của ứng dụng nhà mạng.
    2. Nếu ứng dụng của nhà mạng gặp sự cố hoặc phản hồi bằng RESULT_CANCELED (đây là mã phản hồi mặc định), LPA sẽ huỷ eSIM quy trình kích hoạt.
    3. Nếu ứng dụng của nhà mạng phản hồi bằng thao tác nào đó không phải là RESULT_OK hoặc RESULT_CANCELED, LPA sẽ coi đây là lỗi.

    Vì lý do bảo mật, LPA không nên trực tiếp chấp nhận mã kích hoạt được cung cấp trong ý định kết quả để đảm bảo rằng không phải LPA Người gọi không thể nhận mã kích hoạt từ ứng dụng của nhà mạng.

Chạy quy trình kích hoạt LPA trong một ứng dụng của nhà mạng

Kể từ Android 11, các ứng dụng của nhà mạng có thể dùng API eUICC để khởi động LUI cho eSIM để kích hoạt tài khoản. Phương thức này sẽ hiển thị giao diện người dùng quy trình kích hoạt eSIM của LPA để kích hoạt hồ sơ eSIM. Sau đó, LPA sẽ gửi thông báo phát đi khi hồ sơ eSIM kết thúc.

  1. LPA phải khai báo một hoạt động bao gồm bộ lọc ý định với android.service.euicc.action.START_EUICC_ACTIVATION hành động. Mức độ ưu tiên của bộ lọc ý định phải được đặt thành một giá trị khác 0 trong trường hợp nhiều có các triển khai trên thiết bị. Ví dụ:

    <application>
      ...
    <activity
        android:name=".CarrierAppInitActivity"
        android:exported="true">
    
        <intent-filter android:priority="100">
            <action android:name="android.service.euicc.action.START_EUICC_ACTIVATION" />
        </intent-filter>
    </activity>
      ...
    </application>
    
  2. Ứng dụng của nhà mạng thực hiện công việc bằng cách sử dụng giao diện người dùng riêng. Ví dụ: ghi nhật ký trong người dùng hoặc gửi yêu cầu HTTP đến máy chủ phụ trợ của nhà mạng.

  3. Tại thời điểm này, ứng dụng của nhà mạng phải sẵn sàng cung cấp lệnh kích hoạt mã thông qua việc triển khai ICarrierEuiccProvisioningService. Chiến lược phát hành đĩa đơn ứng dụng của nhà mạng khởi chạy LPA bằng cách gọi startActivityForResult(Intent, int) bằng android.telephony.euicc.action.START_EUICC_ACTIVATION hành động. LPA cũng kiểm tra boolean bổ sung android.telephony.euicc.extra.USE_QR_SCANNER. Nếu giá trị là true, thì LPA chạy trình quét QR để cho phép người dùng quét mã QR của hồ sơ.

  4. Ở phía LPA, LPA liên kết với Phương thức triển khai ICarrierEuiccProvisioningService để tìm nạp lệnh kích hoạt và tải hồ sơ tương ứng xuống. LPA hiển thị tất cả thông tin cần thiết Các thành phần trên giao diện người dùng trong quá trình tải xuống, chẳng hạn như màn hình tải.

  5. Khi quy trình kích hoạt LPA hoàn tất, LPA sẽ phản hồi ứng dụng của nhà mạng có mã kết quả mà ứng dụng của nhà mạng sẽ xử lý onActivityResult(int, int, Intent).

    1. Nếu LPA tải thành công hồ sơ eSIM mới xuống, thiết bị phản hồi bằng RESULT_OK.
    2. Nếu người dùng huỷ kích hoạt hồ sơ eSIM trong LPA, thì thao tác đó phản hồi bằng RESULT_CANCELED.
    3. Nếu LPA phản hồi bằng lệnh không phải là RESULT_OK hoặc RESULT_CANCELED, ứng dụng của nhà mạng sẽ coi đây là lỗi.

    Vì lý do bảo mật, LPA không chấp nhận mã kích hoạt ngay trong ý định đã cung cấp để đảm bảo rằng những phương thức gọi không phải LLP không thể lấy thông tin mã kích hoạt từ ứng dụng của nhà mạng.

Hỗ trợ nhiều eSIM

Đối với các thiết bị chạy Android 10 trở lên, Lớp EuiccManager hỗ trợ thiết bị bằng nhiều eSIM. Các thiết bị có một eSIM duy nhất mà sẽ nâng cấp lên Android 10 không yêu cầu sửa đổi việc triển khai LPA với vai trò là nền tảng tự động liên kết thực thể EuiccManager với eUICC mặc định. Chiến lược phát hành đĩa đơn eUICC mặc định được xác định theo nền tảng đối với các thiết bị có phiên bản HAL (Lớp trừu tượng phần cứng) vô tuyến 1.2 trở lên và theo LPA đối với các thiết bị có phiên bản HAL vô tuyến thấp hơn 1.2.

Yêu cầu

Để hỗ trợ nhiều eSIM, thiết bị phải có nhiều eUICC. Điều này có thể có thể là eUICC tích hợp sẵn hoặc khe cắm SIM thực, trong đó eUICC có thể tháo rời đã chèn.

Cần có Radio HAL phiên bản 1.2 trở lên để hỗ trợ nhiều eSIM. Lớp trừu tượng phần cứng (HAL) qua đài phát thanh phiên bản 1.4 và RadioConfig HAL phiên bản 1.2 được khuyến nghị.

Triển khai

Để hỗ trợ nhiều eSIM (bao gồm cả eUICC có thể tháo rời hoặc SIM có thể lập trình), LPA phải triển khai EuiccService! nhận được ID vị trí tương ứng với ID thẻ do người gọi cung cấp.

Chiến lược phát hành đĩa đơn non_removable_euicc_slots tài nguyên được chỉ định trong arrays.xml là một mảng số nguyên đại diện cho mã nhận dạng vị trí của mã nhận dạng được tích hợp sẵn trong thiết bị eUICC. Bạn phải chỉ định tài nguyên này để cho phép nền tảng xác định liệu một eUICC được chèn có thể tháo rời được hay không.

Ứng dụng của nhà mạng cho thiết bị có nhiều eSIM

Khi tạo ứng dụng của nhà mạng cho một thiết bị có nhiều eSIM, hãy dùng createForCardId trong EuiccManager để tạo đối tượng EuiccManager được ghim vào ID thẻ được cung cấp. Mã thẻ là một giá trị số nguyên nhận dạng duy nhất một UICC hoặc eUICC trên thiết bị.

Để lấy mã thẻ cho eUICC mặc định của thiết bị, hãy sử dụng getCardIdForDefaultEuicc trong TelephonyManager. Phương thức này trả về UNSUPPORTED_CARD_ID nếu phiên bản HAL của đài phát thanh thấp hơn 1.2 và trả về UNINITIALIZED_CARD_ID nếu thiết bị chưa đọc eUICC.

Bạn cũng có thể lấy mã thẻ từ getUiccCardsInfogetUiccSlotsInfo (API hệ thống) trong TelephonyManagergetCardId trong SubscriptionInfo.

Khi một đối tượng EuiccManager được tạo thực thể bằng một mã thẻ cụ thể, tất cả các hoạt động đều được chuyển hướng đến eUICC bằng mã thẻ đó. Nếu eUICC trở thành không kết nối được (ví dụ: khi thiết bị bị tắt hoặc bị xoá) EuiccManager không hoạt động lâu hơn.

Bạn có thể dùng các mã mẫu sau để tạo một ứng dụng của nhà mạng.

Ví dụ 1: Sử dụng gói thuê bao đang hoạt động và tạo thực thể 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);

Ví dụ 2: Lặp lại thông qua UICC và tạo thực thể EuiccManager cho một eUICC có thể xoá

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

Xác nhận kết quả

AOSP không đi kèm với triển khai LPA và bạn sẽ không được dự kiến có sẵn LPA trên tất cả bản dựng Android (không phải mọi điện thoại hỗ trợ eSIM). Cho lý do là vì không có trường hợp thử nghiệm CTS toàn diện. Tuy nhiên, các trường hợp kiểm thử cơ bản có sẵn trong AOSP để đảm bảo các API eUICC bị lộ đều hợp lệ trong các bản dựng Android.

Bạn phải đảm bảo bản dựng vượt qua các trường hợp kiểm thử CTS sau đây (đối với API): /platform/cts/tests/tests/telephony/current/src/android/telephony/euicc/cts.

Các nhà mạng triển khai ứng dụng của nhà mạng nên thực hiện quy trình nội bộ thông thường đảm bảo chất lượng chu kỳ để đảm bảo tất cả các tính năng được triển khai đều hoạt động như mong đợi. Tại tối thiểu, ứng dụng của nhà mạng phải liệt kê được tất cả hồ sơ gói thuê bao thuộc sở hữu của cùng một nhà cung cấp dịch vụ, tải xuống và cài đặt hồ sơ, kích hoạt một dịch vụ trên hồ sơ, chuyển đổi giữa các hồ sơ và xoá hồ sơ.

Nếu tự tạo LPA, bạn sẽ phải trải qua nhiều quy trình nghiêm ngặt hơn kiểm thử. Bạn nên làm việc với nhà cung cấp modem, chip eUICC hoặc nhà cung cấp hệ điều hành eSIM, Nhà cung cấp và nhà cung cấp SM-DP+ để giải quyết các vấn đề và đảm bảo khả năng tương tác của LPA của bạn trong kiến trúc RSP. Bạn nên thử nghiệm thủ công là không thể tránh khỏi. Để có kết quả kiểm thử tốt nhất, bạn nên làm theo Gói thử nghiệm GSMA SGP.23 RSP.