טכנולוגיית כרטיס SIM מוטמע (eSIM או eUICC) מאפשרת למשתמשים בנייד להוריד פרופיל של ספק ולהפעיל את השירות של הספק בלי כרטיס SIM פיזי. זהו מפרט גלובלי שמונע על ידי GSMA ומאפשר הקצאת SIM מרחוק (RSP) לכל מכשיר נייד. החל מ-Android 9, מסגרת Android מספקת ממשקי API סטנדרטיים לגישה ל-eSIM ולניהול פרופילי מינוי ב-eSIM. ממשקי ה-API האלה של eUICC מאפשרים לצדדים שלישיים לפתח אפליקציות משלהם של ספקים ועוזרים מקומיים של פרופילים (LPAs) במכשירי Android עם eSIM.
ה-LPA היא אפליקציית מערכת עצמאית שצריכה להיכלל בתמונת ה-build של Android. בדרך כלל, ה-LPA מנהל את הפרופילים ב-eSIM, כי הוא משמש כגשר בין ה-SM-DP+ (שירות מרוחק שמכין, מאחסן ומעביר חבילות פרופילים למכשירים) לבין שבב ה-eUICC. אפשר לכלול ב-APK של LPA רכיב ממשק משתמש, שנקרא LPA UI או LUI, כדי לספק למשתמש הקצה מקום מרכזי לניהול כל פרופילי המינויים המוטמעים. מסגרת Android מגלה באופן אוטומטי את ה-LPA הטוב ביותר שזמין ומתחברת אליו, ומנתבת את כל הפעולות של ה-eUICC דרך מופע LPA.
איור 1. ארכיטקטורת RSP פשוטה
מפעילים של רשתות סלולריות שמעוניינים ליצור אפליקציה של ספק צריכים לעיין בממשקי ה-API ב-EuiccManager
, שכוללים פעולות ניהול פרופילים ברמה גבוהה, כמו downloadSubscription()
, switchToSubscription()
ו-deleteSubscription()
.
אם אתם יצרני ציוד מקורי של מכשירים שמעוניינים ליצור אפליקציית מערכת משלכם של 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.
יצירת אפליקציה של ספק סלולר
ממשקי eUICC API ב-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 קיימת.
if (mgr == null || !mgr.isEnabled()) {
return;
}
כדי לקבל מידע על חומרת ה-eUICC ועל גרסת מערכת ההפעלה של ה-eSIM:
EuiccInfo info = mgr.getEuiccInfo();
String osVer = info.getOsVersion();
הרבה ממשקי API, כמו downloadSubscription()
ו-switchToSubscription()
, משתמשים ב-PendingIntent
callbacks כי יכול להיות שיחלפו שניות או אפילו דקות עד שהם יסיימו את הפעולה.
ההודעה PendingIntent
נשלחת עם קוד תוצאה במרחב EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_
, שמספק קודי שגיאה שמוגדרים על ידי המסגרת, וגם קוד תוצאה שרירותי ומפורט שמועבר מ-LPA כ-EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE
, וכך מאפשר לאפליקציית הספק לעקוב אחריו למטרות רישום ביומן או ניפוי באגים. הערך של PendingIntent
callback חייב להיות 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*/);
// 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);
מגדירים את ההרשאה ומשתמשים בה ב-AndroidManifest.xml
:
<permission android:protectionLevel="signature" android:name="com.your.company.lpa.permission.BROADCAST" />
<uses-permission android:name="com.your.company.lpa.permission.BROADCAST"/>
כדי לעבור למינוי באמצעות מזהה המינוי:
// 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);
רשימה מלאה של ממשקי EuiccManager
API ודוגמאות קוד זמינה במאמר eUICC APIs.
שגיאות שאפשר לפתור
יש מקרים שבהם המערכת לא מצליחה להשלים את הפעולה ב-eSIM, אבל המשתמש יכול לפתור את השגיאה. לדוגמה, יכול להיות שהפעולה downloadSubscription
תיכשל אם במטא-נתונים של הפרופיל מצוין שנדרש קוד אישור של ספק. או switchToSubscription
עלולה להיכשל אם לאפליקציית הספק יש הרשאות ספק בפרופיל היעד (כלומר, הספק הוא הבעלים של הפרופיל), אבל אין לה הרשאות ספק בפרופיל שמופעל כרגע, ולכן נדרשת הסכמת המשתמש.
במקרים כאלה, הקריאה החוזרת של המתקשר מתבצעת עם EuiccManager#EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR
. הקריאה החוזרת
Intent
מכילה תוספים פנימיים, כך שכשהמתקשר מעביר אותה אל
EuiccManager#startResolutionActivity
, אפשר לבקש רזולוציה דרך ממשק המשתמש של LUI. שימוש בקוד האישור של
הדוגמה שוב,
EuiccManager#startResolutionActivity
מפעיל מסך LUI שמאפשר למשתמש להזין קוד אישור. אחרי הזנת הקוד, פעולת ההורדה מתחדשת. הגישה הזו מספקת לאפליקציה של הספק שליטה מלאה על מועד הצגת ממשק המשתמש, אבל נותנת ל-LPA/LUI שיטה להרחבה להוספת טיפול חדש בבעיות שניתנות לפתרון על ידי המשתמש בעתיד, בלי שיהיה צורך לשנות את אפליקציות הלקוח.
ב-Android 9 מוגדרות השגיאות הבאות שניתנות לפתרון ב-EuiccService
, ושממשק המשתמש המקומי צריך לטפל בהן:
/**
* 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) של הפרופיל, ומעניקה הרשאה לאפליקציות שנחתמו על ידי האישורים האלה לשלוח קריאות ל-EuiccManager
APIs. התהליך הכללי מתואר בהמשך:
- המפעיל חותם על קובץ ה-APK של אפליקציית הספק. הכלי apksigner מצרף את אישור המפתח הציבורי לקובץ ה-APK.
המפעיל או SM-DP+ מכינים פרופיל ואת המטא-נתונים שלו, כולל קובץ ARF שמכיל:
- חתימה (SHA-1 או SHA-256) של אישור המפתח הציבורי של אפליקציית הספק (נדרש)
- שם החבילה של אפליקציית הספק (מומלץ מאוד)
אפליקציית הספק מנסה לבצע פעולה ב-eUICC באמצעות
EuiccManager
API.פלטפורמת 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) משלהם, שצריך להיות מחובר לממשקי Android Euicc API. בקטעים הבאים מופיעה סקירה כללית קצרה על יצירת אפליקציית LPA ושילובה במערכת Android.
דרישות חומרה/מודם
מערכת ההפעלה של ה-LPA ושל ה-eSIM בשבב ה-eUICC צריכה לתמוך לפחות ב-GSMA RSP (הקצאת SIM מרחוק) בגרסה 2.0 או 2.2. כדאי גם לתכנן שימוש בשרתי SM-DP+ ו-SM-DS עם גרסת RSP תואמת. למידע מפורט על ארכיטקטורת ה-RSP, אפשר לעיין במאמר GSMA SGP.21 RSP Architecture Specification.
בנוסף, כדי לשלב עם ממשקי ה-API של eUICC ב-Android 9, מודם המכשיר צריך לשלוח יכולות מסוף עם תמיכה ביכולות eUICC מוצפנות (ניהול פרופילים מקומי והורדת פרופילים). בנוסף, צריך להטמיע את השיטות הבאות:
- IRadio HAL v1.1:
setSimPower
IRadio HAL v1.2:
getIccCardStatus
IRadioConfig HAL v1.0:
getSimSlotsStatus
IRadioConfig AIDL v1.0:
getAllowedCarriers
ה-LPA של Google צריך לדעת את סטטוס הנעילה של הספק כדי לאפשר הורדה או העברה של eSIM רק לספק המורשה. אחרת, יכול להיות שהמשתמשים יורידו ויעבירו כרטיס SIM, ורק אחר כך יבינו שהמכשיר נעול לספק אחר.
ספקים או יצרני ציוד מקורי (OEM) צריכים להטמיע את IRadioSim.getAllowedCarriers() HAL API.
ספק RIL / Modem יאכלס את סטטוס הנעילה ואת carrierId של הספק שאליו המכשיר נעול כחלק מ-IRadioSimResponse.getAllowedCarriersResponse()HAL API.
המודם צריך לזהות את ה-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
כדי להבטיח שרק המערכת תוכל לקשר אותו. השירות צריך לכלול גם מסנן Intent עם הפעולה 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 הפעיל ומבצעת איתו אינטראקציה לפי הצורך כדי לתמוך בממשקי Android eUICC API. מתבצעת שאילתה ב-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
. לכל אחד מהם צריך להיות מסנן Intent עם הפעולה המתאימה, הקטגוריה 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
ואחד שמספק פעילויות של ממשק משתמש לשפה) היא החלטה עיצובית.
EuiccCardManager
EuiccCardManager
הוא הממשק לתקשורת עם שבב ה-eSIM. היא מספקת פונקציות ES10 (כפי שמתואר במפרט GSMA RSP) ומטפלת בפקודות בקשות/תגובות APDU ברמה נמוכה, וגם בניתוח ASN.1.
EuiccCardManager
הוא ממשק API של המערכת, ורק אפליקציות עם הרשאות מערכת יכולות לשלוח אליו קריאות.
איור 2. גם אפליקציית הספק וגם LPA משתמשות בממשקי Euicc API
כדי להשתמש בממשקי ה-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 ייעודי אחר. כשמשתמשים בממשקי EuiccCardManager
API, המתקשר (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
כדי לקבל את קוד ההפעלה מאפליקציית הספק על ידי העברת ההטמעה של מחלקת ה-stub 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, אפליקציה עם הרשאות מערכת, תוכל להתחבר אליו. השירות צריך לכלול גם מסנן Intent עם הפעולה 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
ומטמיעים את ה-methods 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
Intent לחבילת אפליקציית הספק שמכילה את הפעולה. (צריך להגן על מקלט אפליקציית הספק בהצהרת המניפסט באמצעותandroid:permission="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
כדי למנוע קבלת intents מאפליקציות שאינן 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 לא צריך לקבל ישירות קוד הפעלה שסופק ב-intent של התוצאה, כדי לוודא שגורמים שקוראים ל-LPA ולא מורשים לא יכולים לקבל קוד הפעלה מאפליקציית הספק.
- אם אפליקציית הספק משיבה עם
הפעלת תהליך ההפעלה של LPA באפליקציית ספק
החל מ-Android 11, אפליקציות של ספקים יכולות להשתמש בממשקי eUICC API כדי להפעיל ממשק משתמש מקומי להפעלת eSIM. בשיטה הזו, ממשק המשתמש של תהליך הפעלת ה-eSIM של ה-LPA מוצג כדי להפעיל את פרופיל ה-eSIM. לאחר מכן, ה-LPA שולח שידור כשההפעלה של פרופיל ה-eSIM מסתיימת.
ה-LPA צריך להצהיר על פעילות, כולל מסנן Intent עם הפעולה
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 לא מקבל קוד הפעלה ישירות ב-intent שסופק, כדי להבטיח שגורמים שמתקשרים שלא משתמשים ב-LPA לא יוכלו לקבל את קוד ההפעלה מאפליקציית הספק.
- אם ה-LPA מצליח להוריד את פרופיל ה-eSIM החדש, הוא מגיב עם
תמיכה בכמה כרטיסי eSIM
במכשירים עם Android מגרסה 10 ואילך, המחלקה EuiccManager
תומכת במכשירים עם כמה כרטיסי eSIM. במכשירים עם כרטיס eSIM יחיד שמשדרגים ל-Android 10, לא נדרש שינוי בהטמעה של ה-LPA, כי הפלטפורמה משייכת באופן אוטומטי את מופע EuiccManager
ל-eUICC שמוגדר כברירת מחדל. ה-eUICC שמוגדר כברירת מחדל נקבע על ידי הפלטפורמה במכשירים עם radio HAL מגרסה 1.2 ואילך, ועל ידי ה-LPA במכשירים עם radio HAL מגרסאות נמוכות מ-1.2.
דרישות
כדי לתמוך בכמה כרטיסי eSIM, במכשיר צריכים להיות יותר מ-eUICC אחד. זה יכול להיות eUICC מובנה או חריץ לכרטיס SIM פיזי שאפשר להכניס אליו כרטיסי eUICC נשלפים.
כדי לתמוך בכמה כרטיסי eSIM, נדרשת גרסה 1.2 ומעלה של Radio HAL. מומלץ להשתמש ב-Radio HAL בגרסה 1.4 וב-RadioConfig HAL בגרסה 1.2.
הטמעה
כדי לתמוך בכמה כרטיסי eSIM (כולל כרטיסי eUICC נשלפים או כרטיסי SIM ניתנים לתכנות), רכיב ה-LPA צריך להטמיע את EuiccService
, שמקבל את מזהה החריץ שמתאים למזהה הכרטיס שסופק על ידי המתקשר.
המשאב non_removable_euicc_slots
שצוין ב-arrays.xml
הוא מערך של מספרים שלמים שמייצגים את מזהי המשבצות של כרטיסי ה-eUICC המובנים במכשיר. חובה לציין את המשאב הזה כדי שהפלטפורמה תוכל לקבוע אם כרטיס ה-eUICC שהוכנס ניתן להסרה או לא.
אפליקציה של ספק סלולר למכשיר עם כמה כרטיסי 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 משלכם, אתם צריכים לבצע בדיקות קפדניות הרבה יותר. כדי לפתור בעיות ולהבטיח יכולת פעולה הדדית של LPA במסגרת ארכיטקטורת ה-RSP, צריך לעבוד עם ספק המודם, ספק שבב ה-eUICC או מערכת ההפעלה של ה-eSIM, ספקי SM-DP+ וספקי סלולר. כמות מסוימת של בדיקות ידניות היא בלתי נמנעת. כדי לקבל את הכיסוי הטוב ביותר של הבדיקה, צריך לפעול לפי תוכנית הבדיקה GSMA SGP.23 RSP.