1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.telephony.mockmodem;
18 
19 import android.content.Context;
20 import android.hardware.radio.sim.AppStatus;
21 import android.hardware.radio.sim.PinState;
22 import android.util.Log;
23 import android.util.Xml;
24 
25 import org.xmlpull.v1.XmlPullParser;
26 
27 import java.io.InputStream;
28 import java.util.ArrayList;
29 import java.util.Locale;
30 
31 public class MockSimService {
32     /* Support SIM card identify */
33     public static final int MOCK_SIM_PROFILE_ID_DEFAULT = 0; // SIM Absent
34     public static final int MOCK_SIM_PROFILE_ID_TWN_CHT = 1;
35     public static final int MOCK_SIM_PROFILE_ID_TWN_FET = 2;
36     public static final int MOCK_SIM_PROFILE_ID_US_FI = 3;
37     public static final int MOCK_SIM_PROFILE_ID_MAX = 4;
38 
39     /* Type of SIM IO command */
40     public static final int COMMAND_READ_BINARY = 0xb0;
41     public static final int COMMAND_GET_RESPONSE = 0xc0;
42 
43     /* EF Id definition */
44     public static final int EF_ICCID = 0x2FE2;
45     public static final int EF_IMSI = 0x6F07;
46     public static final int EF_GID1 = 0x6F3E;
47 
48     /* SIM profile XML TAG definition */
49     private static final String MOCK_SIM_TAG = "MockSim";
50     private static final String MOCK_SIM_PROFILE_TAG = "MockSimProfile";
51     private static final String MOCK_PIN_PROFILE_TAG = "PinProfile";
52     private static final String MOCK_PIN1_STATE_TAG = "Pin1State";
53     private static final String MOCK_PIN2_STATE_TAG = "Pin2State";
54     private static final String MOCK_FACILITY_LOCK_TAG = "FacilityLock";
55     private static final String MOCK_FACILITY_LOCK_FD_TAG = "FD";
56     private static final String MOCK_FACILITY_LOCK_SC_TAG = "SC";
57     private static final String MOCK_MF_TAG = "MF";
58     private static final String MOCK_EF_TAG = "EF";
59     private static final String MOCK_EF_DIR_TAG = "EFDIR";
60     private static final String MOCK_ADF_TAG = "ADF";
61 
62     /* Support SIM slot */
63     private static final int MOCK_SIM_SLOT_1 = 0;
64     private static final int MOCK_SIM_SLOT_2 = 1;
65     private static final int MOCK_SIM_SLOT_3 = 2;
66     public static final int MOCK_SIM_SLOT_MIN = 1;
67     public static final int MOCK_SIM_SLOT_MAX = 3;
68 
69     /* Default value definition */
70     private static final int MOCK_SIM_DEFAULT_SLOTID = MOCK_SIM_SLOT_1;
71     private static final int DEFAULT_NUM_OF_SIM_APP = 0;
72     private static final int DEFAULT_GSM_APP_IDX = -1;
73     private static final int DEFAULT_CDMA_APP_IDX = -1;
74     private static final int DEFAULT_IMS_APP_IDX = -1;
75     private static final int DEFAULT_NUM_OF_SIM_PORT_INFO = 1;
76     // SIM1 slot status - physical SIM
77     private static final int DEFAULT_SIM1_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
78     private static final boolean DEFAULT_SIM1_CARD_PRESENT = false;
79     private static final String DEFAULT_SIM1_ATR = "";
80     private static final String DEFAULT_SIM1_EID = "";
81     private static final boolean DEFAULT_SIM1_PORT_ACTIVE = true;
82     private static final int DEFAULT_SIM1_PORT_ID = 0;
83     private static final int DEFAULT_SIM1_LOGICAL_SLOT_ID = 0;
84     private static final int DEFAULT_SIM1_UNIVERSAL_PIN_STATE = PinState.UNKNOWN;
85     // SIM2 slot status - eSIM
86     private static final int DEFAULT_SIM2_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
87     private static final boolean DEFAULT_SIM2_CARD_PRESENT = true;
88     private static final String DEFAULT_SIM2_ATR =
89             "3B9F97C00A3FC6828031E073FE211F65D002341512810F51";
90     private static final String DEFAULT_SIM2_EID = "89033023426200000000005430099507";
91     private static final boolean DEFAULT_SIM2_PORT_ACTIVE = true;
92     private static final int DEFAULT_SIM2_PORT_ID = 0;
93     private static final int DEFAULT_SIM2_LOGICAL_SLOT_ID = 1;
94     private static final int DEFAULT_SIM2_UNIVERSAL_PIN_STATE = PinState.DISABLED;
95     // SIM3 slot status - eSIM
96     private static final int DEFAULT_SIM3_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
97     private static final boolean DEFAULT_SIM3_CARD_PRESENT = true;
98     private static final String DEFAULT_SIM3_ATR =
99             "3B9F97C00AB1FE453FC6838031E073FE211F65D002341569810F21";
100     private static final String DEFAULT_SIM3_EID = "89033023427100000000007980324395";
101     private static final boolean DEFAULT_SIM3_PORT_ACTIVE = false;
102     private static final int DEFAULT_SIM3_PORT_ID = 0;
103     private static final int DEFAULT_SIM3_LOGICAL_SLOT_ID = -1;
104     private static final int DEFAULT_SIM3_UNIVERSAL_PIN_STATE = PinState.DISABLED;
105 
106     private String mTag = "MockSimService";
107     private Context mContext;
108 
109     // SIM Slot status
110     private int mPhysicalSlotId;
111     private int mLogicalSlotId;
112     private int mSlotPortId;
113     private boolean mIsSlotPortActive;
114     private boolean mIsCardPresent;
115 
116     /* SIM profile info */
117     private SimProfileInfo[] mSimProfileInfoList;
118 
119     // SIM card data
120     private int mSimProfileId;
121     private String mEID;
122     private String mATR;
123     private int mUniversalPinState;
124 
125     private AppStatus[] mSimApp;
126     private ArrayList<SimAppData> mSimAppList;
127 
128     public class SimAppData {
129         private static final int EF_INFO_DATA = 0;
130         private static final int EF_BINARY_DATA = 1;
131 
132         private int mSimAppId;
133         private String mAid;
134         private boolean mIsCurrentActive;
135         private String mPath;
136         private int mFdnStatus;
137         private int mPin1State;
138         private String mImsi;
139         private String mMcc;
140         private String mMnc;
141         private String mMsin;
142         private String[] mIccid;
143         private String[] mGid1;
144 
initSimAppData(int simappid, String aid, String path, boolean status)145         private void initSimAppData(int simappid, String aid, String path, boolean status) {
146             mSimAppId = simappid;
147             mAid = aid;
148             mIsCurrentActive = status;
149             mPath = path;
150             mIccid = new String[2];
151             mGid1 = new String[2];
152         }
153 
SimAppData(int simappid, String aid, String path)154         public SimAppData(int simappid, String aid, String path) {
155             initSimAppData(simappid, aid, path, false);
156         }
157 
SimAppData(int simappid, String aid, String path, boolean status)158         public SimAppData(int simappid, String aid, String path, boolean status) {
159             initSimAppData(simappid, aid, path, status);
160         }
161 
getSimAppId()162         public int getSimAppId() {
163             return mSimAppId;
164         }
165 
getAid()166         public String getAid() {
167             return mAid;
168         }
169 
isCurrentActive()170         public boolean isCurrentActive() {
171             return mIsCurrentActive;
172         }
173 
getPath()174         public String getPath() {
175             return mPath;
176         }
177 
getFdnStatus()178         public int getFdnStatus() {
179             return mFdnStatus;
180         }
181 
setFdnStatus(int status)182         public void setFdnStatus(int status) {
183             mFdnStatus = status;
184         }
185 
getPin1State()186         public int getPin1State() {
187             return mPin1State;
188         }
189 
setPin1State(int state)190         public void setPin1State(int state) {
191             mPin1State = state;
192         }
193 
getImsi()194         public String getImsi() {
195             return mMcc + mMnc + mMsin;
196         }
197 
setImsi(String mcc, String mnc, String msin)198         public void setImsi(String mcc, String mnc, String msin) {
199             setMcc(mcc);
200             setMnc(mnc);
201             setMsin(msin);
202         }
203 
getMcc()204         public String getMcc() {
205             return mMcc;
206         }
207 
setMcc(String mcc)208         public void setMcc(String mcc) {
209             mMcc = mcc;
210         }
211 
getMnc()212         public String getMnc() {
213             return mMnc;
214         }
215 
setMnc(String mnc)216         public void setMnc(String mnc) {
217             mMnc = mnc;
218         }
219 
getMsin()220         public String getMsin() {
221             return mMsin;
222         }
223 
setMsin(String msin)224         public void setMsin(String msin) {
225             mMsin = msin;
226         }
227 
getIccidInfo()228         public String getIccidInfo() {
229             return mIccid[EF_INFO_DATA];
230         }
231 
setIccidInfo(String info)232         public void setIccidInfo(String info) {
233             mIccid[EF_INFO_DATA] = info;
234         }
235 
getIccid()236         public String getIccid() {
237             return mIccid[EF_BINARY_DATA];
238         }
239 
setIccid(String iccid)240         public void setIccid(String iccid) {
241             mIccid[EF_BINARY_DATA] = iccid;
242         }
243 
getGid1Info()244         public String getGid1Info() {
245             return mGid1[EF_INFO_DATA];
246         }
247 
setGid1Info(String info)248         public void setGid1Info(String info) {
249             mGid1[EF_INFO_DATA] = info;
250         }
251 
getGid1()252         public String getGid1() {
253             return mGid1[EF_BINARY_DATA];
254         }
255 
setGid1(String gid1)256         public void setGid1(String gid1) {
257             mGid1[EF_BINARY_DATA] = gid1;
258         }
259     }
260 
261     public class SimProfileInfo {
262         private int mSimProfileId;
263         private int mNumOfSimApp;
264         private int mGsmAppIndex;
265         private int mCdmaAppIndex;
266         private int mImsAppIndex;
267         private String mXmlFile;
268 
SimProfileInfo(int profileid)269         public SimProfileInfo(int profileid) {
270             mSimProfileId = profileid;
271             mNumOfSimApp = DEFAULT_NUM_OF_SIM_APP;
272             mGsmAppIndex = DEFAULT_GSM_APP_IDX;
273             mCdmaAppIndex = DEFAULT_CDMA_APP_IDX;
274             mImsAppIndex = DEFAULT_IMS_APP_IDX;
275             mXmlFile = "";
276         }
277 
getNumOfSimApp()278         public int getNumOfSimApp() {
279             return mNumOfSimApp;
280         }
281 
getGsmAppIndex()282         public int getGsmAppIndex() {
283             return mGsmAppIndex;
284         }
285 
getCdmaAppIndex()286         public int getCdmaAppIndex() {
287             return mCdmaAppIndex;
288         }
289 
getImsAppIndex()290         public int getImsAppIndex() {
291             return mImsAppIndex;
292         }
293 
getXmlFile()294         public String getXmlFile() {
295             return mXmlFile;
296         }
297 
setNumOfSimApp(int number)298         public void setNumOfSimApp(int number) {
299             mNumOfSimApp = number;
300         }
301 
setGsmAppIndex(int index)302         public void setGsmAppIndex(int index) {
303             mGsmAppIndex = index;
304         }
305 
setCdmaAppIndex(int index)306         public void setCdmaAppIndex(int index) {
307             mCdmaAppIndex = index;
308         }
309 
setImsAppIndex(int index)310         public void setImsAppIndex(int index) {
311             mImsAppIndex = index;
312         }
313 
setXmlFile(String file)314         public void setXmlFile(String file) {
315             mXmlFile = file;
316         }
317     }
318 
MockSimService(Context context, int slotId)319     public MockSimService(Context context, int slotId) {
320         mContext = context;
321         int simprofile = DEFAULT_SIM1_PROFILE_ID;
322 
323         if (slotId >= MOCK_SIM_SLOT_MAX) {
324             Log.e(
325                     mTag,
326                     "Invalid slot id("
327                             + slotId
328                             + "). Using default slot id("
329                             + MOCK_SIM_DEFAULT_SLOTID
330                             + ").");
331             slotId = MOCK_SIM_DEFAULT_SLOTID;
332         }
333 
334         // Init default SIM profile id
335         mTag = mTag + "-" + slotId;
336         switch (slotId) {
337             case MOCK_SIM_SLOT_1:
338                 simprofile = DEFAULT_SIM1_PROFILE_ID;
339                 break;
340             case MOCK_SIM_SLOT_2:
341                 simprofile = DEFAULT_SIM2_PROFILE_ID;
342                 break;
343             case MOCK_SIM_SLOT_3:
344                 simprofile = DEFAULT_SIM3_PROFILE_ID;
345                 break;
346         }
347 
348         // Initial support SIM profile list
349         mSimProfileInfoList = new SimProfileInfo[MOCK_SIM_PROFILE_ID_MAX];
350         for (int idx = 0; idx < MOCK_SIM_PROFILE_ID_MAX; idx++) {
351             Log.d(mTag, "Create sim profile id = " + idx);
352             mSimProfileInfoList[idx] = new SimProfileInfo(idx);
353             switch (idx) {
354                 case MOCK_SIM_PROFILE_ID_TWN_CHT:
355                     mSimProfileInfoList[idx].setXmlFile("mock_sim_tw_cht.xml");
356                     break;
357                 case MOCK_SIM_PROFILE_ID_TWN_FET:
358                     mSimProfileInfoList[idx].setXmlFile("mock_sim_tw_fet.xml");
359                     break;
360                 case MOCK_SIM_PROFILE_ID_US_FI:
361                     mSimProfileInfoList[idx].setXmlFile("mock_sim_us_fi.xml");
362                     break;
363                 default:
364                     break;
365             }
366         }
367 
368         // Initiate SIM card with default profile
369         initMockSimCard(slotId, simprofile);
370     }
371 
initMockSimCard(int slotId, int simProfileId)372     private void initMockSimCard(int slotId, int simProfileId) {
373         if (slotId > MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT) {
374             Log.e(
375                     mTag,
376                     "Physical slot id("
377                             + slotId
378                             + ") is invalid. Using default slot id("
379                             + MOCK_SIM_DEFAULT_SLOTID
380                             + ").");
381             mPhysicalSlotId = MOCK_SIM_DEFAULT_SLOTID;
382         } else {
383             mPhysicalSlotId = slotId;
384         }
385         if (simProfileId >= 0 && simProfileId < MOCK_SIM_PROFILE_ID_MAX) {
386             mSimProfileId = simProfileId;
387             Log.i(
388                     mTag,
389                     "Load SIM profile ID: "
390                             + mSimProfileId
391                             + " into physical slot["
392                             + mPhysicalSlotId
393                             + "]");
394         } else {
395             mSimProfileId = MOCK_SIM_PROFILE_ID_DEFAULT;
396             Log.e(
397                     mTag,
398                     "SIM Absent on physical slot["
399                             + mPhysicalSlotId
400                             + "]. Not support SIM card ID: "
401                             + mSimProfileId);
402         }
403 
404         // Initiate slot status
405         initMockSimSlot();
406 
407         // Load SIM profile data
408         loadMockSimCard();
409     }
410 
initMockSimSlot()411     private void initMockSimSlot() {
412         switch (mPhysicalSlotId) {
413             case MOCK_SIM_SLOT_1:
414                 mLogicalSlotId = DEFAULT_SIM1_LOGICAL_SLOT_ID;
415                 mSlotPortId = DEFAULT_SIM1_PORT_ID;
416                 mIsSlotPortActive = DEFAULT_SIM1_PORT_ACTIVE;
417                 mIsCardPresent = DEFAULT_SIM1_CARD_PRESENT;
418                 break;
419             case MOCK_SIM_SLOT_2:
420                 mLogicalSlotId = DEFAULT_SIM2_LOGICAL_SLOT_ID;
421                 mSlotPortId = DEFAULT_SIM2_PORT_ID;
422                 mIsSlotPortActive = DEFAULT_SIM2_PORT_ACTIVE;
423                 mIsCardPresent = DEFAULT_SIM2_CARD_PRESENT;
424                 break;
425             case MOCK_SIM_SLOT_3:
426                 mLogicalSlotId = DEFAULT_SIM3_LOGICAL_SLOT_ID;
427                 mSlotPortId = DEFAULT_SIM3_PORT_ID;
428                 mIsSlotPortActive = DEFAULT_SIM3_PORT_ACTIVE;
429                 mIsCardPresent = DEFAULT_SIM3_CARD_PRESENT;
430                 break;
431         }
432     }
433 
convertMockSimPinState(String pinstate)434     private int convertMockSimPinState(String pinstate) {
435         int mocksim_pinstate = PinState.UNKNOWN;
436         switch (pinstate) {
437             case "PINSTATE_UNKNOWN":
438                 mocksim_pinstate = PinState.UNKNOWN;
439                 break;
440             case "PINSTATE_ENABLED_NOT_VERIFIED":
441                 mocksim_pinstate = PinState.ENABLED_NOT_VERIFIED;
442                 break;
443             case "PINSTATE_ENABLED_VERIFIED":
444                 mocksim_pinstate = PinState.ENABLED_VERIFIED;
445                 break;
446             case "PINSTATE_DISABLED":
447                 mocksim_pinstate = PinState.DISABLED;
448                 break;
449             case "PINSTATE_ENABLED_BLOCKED":
450                 mocksim_pinstate = PinState.ENABLED_BLOCKED;
451                 break;
452             case "PINSTATE_ENABLED_PERM_BLOCKED":
453                 mocksim_pinstate = PinState.ENABLED_PERM_BLOCKED;
454                 break;
455         }
456 
457         return mocksim_pinstate;
458     }
459 
convertMockSimAppType(String apptype)460     private int convertMockSimAppType(String apptype) {
461         int mocksim_apptype = AppStatus.APP_TYPE_UNKNOWN;
462         switch (apptype) {
463             case "APPTYPE_UNKNOWN":
464                 mocksim_apptype = AppStatus.APP_TYPE_UNKNOWN;
465                 break;
466             case "APPTYPE_SIM":
467                 mocksim_apptype = AppStatus.APP_TYPE_SIM;
468                 break;
469             case "APPTYPE_USIM":
470                 mocksim_apptype = AppStatus.APP_TYPE_USIM;
471                 break;
472             case "APPTYPE_RUIM":
473                 mocksim_apptype = AppStatus.APP_TYPE_RUIM;
474                 break;
475             case "APPTYPE_CSIM":
476                 mocksim_apptype = AppStatus.APP_TYPE_CSIM;
477                 break;
478             case "APPTYPE_ISIM":
479                 mocksim_apptype = AppStatus.APP_TYPE_ISIM;
480                 break;
481         }
482 
483         return mocksim_apptype;
484     }
485 
convertMockSimAppState(String appstate)486     private int convertMockSimAppState(String appstate) {
487         int mocksim_appstate = AppStatus.APP_STATE_UNKNOWN;
488         switch (appstate) {
489             case "APPSTATE_UNKNOWN":
490                 mocksim_appstate = AppStatus.APP_STATE_UNKNOWN;
491                 break;
492             case "APPSTATE_DETECTED":
493                 mocksim_appstate = AppStatus.APP_STATE_DETECTED;
494                 break;
495             case "APPSTATE_PIN":
496                 mocksim_appstate = AppStatus.APP_STATE_PIN;
497                 break;
498             case "APPSTATE_PUK":
499                 mocksim_appstate = AppStatus.APP_STATE_PUK;
500                 break;
501             case "APPSTATE_SUBSCRIPTION_PERSO":
502                 mocksim_appstate = AppStatus.APP_STATE_SUBSCRIPTION_PERSO;
503                 break;
504             case "APPSTATE_READY":
505                 mocksim_appstate = AppStatus.APP_STATE_READY;
506                 break;
507         }
508         return mocksim_appstate;
509     }
510 
convertMockSimFacilityLock(String lock)511     private int convertMockSimFacilityLock(String lock) {
512         int facilitylock = 0;
513         switch (lock) {
514             case "LOCK_ENABLED":
515                 facilitylock = 1;
516                 break;
517             case "LOCK_DISABLED":
518                 facilitylock = 0;
519                 break;
520         }
521         return facilitylock;
522     }
523 
getSimAppDataIndexByAid(String aid)524     private int getSimAppDataIndexByAid(String aid) {
525         int idx;
526         for (idx = 0; idx < mSimAppList.size(); idx++) {
527             if (aid.equals(mSimAppList.get(idx).getAid())) {
528                 break;
529             }
530         }
531         return idx;
532     }
533 
extractImsi(String imsi, int mncDigit)534     private String[] extractImsi(String imsi, int mncDigit) {
535         String[] result = null;
536 
537         Log.d(mTag, "IMSI = " + imsi + ", mnc-digit = " + mncDigit);
538 
539         if (imsi.length() > 15 && imsi.length() < 5) {
540             Log.d(mTag, "Invalid IMSI length.");
541             return result;
542         }
543 
544         if (mncDigit != 2 && mncDigit != 3) {
545             Log.d(mTag, "Invalid mnc length.");
546             return result;
547         }
548 
549         result = new String[3];
550         result[0] = imsi.substring(0, 3); // MCC
551         result[1] = imsi.substring(3, 3 + mncDigit); // MNC
552         result[2] = imsi.substring(3 + mncDigit, imsi.length()); // MSIN
553 
554         Log.d(mTag, "MCC = " + result[0] + " MNC = " + result[1] + " MSIN = " + result[2]);
555 
556         return result;
557     }
558 
storeEfData( String aid, String name, String id, String command, String[] value)559     private boolean storeEfData(
560             String aid, String name, String id, String command, String[] value) {
561         boolean result = true;
562 
563         if (value == null) {
564             Log.e(mTag, "Invalid value of EF field - " + name + "(" + id + ")");
565             return false;
566         }
567 
568         switch (name) {
569             case "EF_IMSI":
570                 if (value.length == 3
571                         && value[0] != null
572                         && value[0].length() == 3
573                         && value[1] != null
574                         && (value[1].length() == 2 || value[1].length() == 3)
575                         && value[2] != null
576                         && value[2].length() > 0
577                         && (value[0].length() + value[1].length() + value[2].length() <= 15)) {
578                     mSimAppList
579                             .get(getSimAppDataIndexByAid(aid))
580                             .setImsi(value[0], value[1], value[2]);
581                 } else {
582                     result = false;
583                     Log.e(mTag, "Invalid value for EF field - " + name + "(" + id + ")");
584                 }
585                 break;
586             case "EF_ICCID":
587                 if (command.length() > 2
588                         && Integer.parseInt(command.substring(2), 16) == COMMAND_READ_BINARY) {
589                     mSimAppList.get(getSimAppDataIndexByAid(aid)).setIccid(value[0]);
590                 } else if (command.length() > 2
591                         && Integer.parseInt(command.substring(2), 16) == COMMAND_GET_RESPONSE) {
592                     mSimAppList.get(getSimAppDataIndexByAid(aid)).setIccidInfo(value[0]);
593                 } else {
594                     Log.e(mTag, "No valid Iccid data found");
595                     result = false;
596                 }
597                 break;
598             case "EF_GID1":
599                 if (command.length() > 2
600                         && Integer.parseInt(command.substring(2), 16) == COMMAND_READ_BINARY) {
601                     mSimAppList.get(getSimAppDataIndexByAid(aid)).setGid1(value[0]);
602                 } else if (command.length() > 2
603                         && Integer.parseInt(command.substring(2), 16) == COMMAND_GET_RESPONSE) {
604                     mSimAppList.get(getSimAppDataIndexByAid(aid)).setGid1Info(value[0]);
605                 } else {
606                     Log.e(mTag, "No valid GID1 found");
607                     result = false;
608                 }
609                 break;
610             default:
611                 result = false;
612                 Log.w(mTag, "Not support EF field - " + name + "(" + id + ")");
613                 break;
614         }
615         return result;
616     }
617 
loadSimProfileFromXml()618     private boolean loadSimProfileFromXml() {
619         boolean result = true;
620 
621         if (mSimProfileInfoList == null) {
622             Log.e(mTag, "No support SIM profile list.");
623             return false;
624         }
625 
626         try {
627             String file = mSimProfileInfoList[mSimProfileId].getXmlFile();
628             int event;
629             XmlPullParser parser = Xml.newPullParser();
630             InputStream input;
631             boolean mocksim_validation = false;
632             boolean mocksim_pf_validatiion = false;
633             boolean mocksim_mf_validation = false;
634             int appidx = 0;
635             int fd_lock = 0;
636             int sc_lock = 0;
637             String adf_aid = "";
638 
639             input = mContext.getAssets().open(file);
640             parser.setInput(input, null);
641             while (result && (event = parser.next()) != XmlPullParser.END_DOCUMENT) {
642                 switch (event) {
643                     case XmlPullParser.START_TAG:
644                         if (MOCK_SIM_TAG.equals(parser.getName())) {
645                             int numofapp = Integer.parseInt(parser.getAttributeValue(0));
646                             mATR = parser.getAttributeValue(1);
647                             Log.d(
648                                     mTag,
649                                     "Found "
650                                             + MOCK_SIM_TAG
651                                             + ": numofapp = "
652                                             + numofapp
653                                             + " atr = "
654                                             + mATR);
655                             mSimApp = new AppStatus[numofapp];
656                             if (mSimApp == null) {
657                                 Log.e(mTag, "Create SIM app failed!");
658                                 result = false;
659                                 break;
660                             }
661                             mocksim_validation = true;
662                         } else if (mocksim_validation
663                                 && MOCK_SIM_PROFILE_TAG.equals(parser.getName())
664                                 && appidx < mSimApp.length) {
665                             int id = Integer.parseInt(parser.getAttributeValue(0));
666                             int type = convertMockSimAppType(parser.getAttributeValue(1));
667                             mSimApp[appidx] = new AppStatus();
668                             mSimApp[appidx].appType = type;
669                             switch (type) {
670                                 case AppStatus.APP_TYPE_SIM:
671                                 case AppStatus.APP_TYPE_USIM:
672                                     mSimProfileInfoList[mSimProfileId].setGsmAppIndex(id);
673                                     break;
674                                 case AppStatus.APP_TYPE_CSIM:
675                                 case AppStatus.APP_TYPE_RUIM:
676                                     mSimProfileInfoList[mSimProfileId].setCdmaAppIndex(id);
677                                     break;
678                                 case AppStatus.APP_TYPE_ISIM:
679                                     mSimProfileInfoList[mSimProfileId].setImsAppIndex(id);
680                                     break;
681                             }
682                             Log.d(
683                                     mTag,
684                                     "Found ["
685                                             + MOCK_SIM_PROFILE_TAG
686                                             + "]: id = "
687                                             + id
688                                             + " type = "
689                                             + parser.getAttributeValue(1)
690                                             + " ("
691                                             + type
692                                             + ")========");
693                             mocksim_pf_validatiion = true;
694                         } else if (mocksim_validation
695                                 && mocksim_pf_validatiion
696                                 && MOCK_PIN_PROFILE_TAG.equals(parser.getName())) {
697                             int appstate = convertMockSimAppState(parser.getAttributeValue(0));
698                             mSimApp[appidx].appState = appstate;
699                             Log.d(
700                                     mTag,
701                                     "Found "
702                                             + MOCK_PIN_PROFILE_TAG
703                                             + ": appstate = "
704                                             + parser.getAttributeValue(0)
705                                             + " ("
706                                             + appstate
707                                             + ")");
708                         } else if (mocksim_validation
709                                 && mocksim_pf_validatiion
710                                 && MOCK_PIN1_STATE_TAG.equals(parser.getName())) {
711                             String state = parser.nextText();
712                             int pin1state = convertMockSimPinState(state);
713                             mSimApp[appidx].pin1 = pin1state;
714                             Log.d(
715                                     mTag,
716                                     "Found "
717                                             + MOCK_PIN1_STATE_TAG
718                                             + " = "
719                                             + state
720                                             + " ("
721                                             + pin1state
722                                             + ")");
723                         } else if (mocksim_validation
724                                 && mocksim_pf_validatiion
725                                 && MOCK_PIN2_STATE_TAG.equals(parser.getName())) {
726                             String state = parser.nextText();
727                             int pin2state = convertMockSimPinState(state);
728                             Log.d(
729                                     mTag,
730                                     "Found "
731                                             + MOCK_PIN2_STATE_TAG
732                                             + " = "
733                                             + state
734                                             + " ("
735                                             + pin2state
736                                             + ")");
737                             mSimApp[appidx].pin2 = pin2state;
738                         } else if (mocksim_validation
739                                 && mocksim_pf_validatiion
740                                 && MOCK_FACILITY_LOCK_FD_TAG.equals(parser.getName())) {
741                             fd_lock = convertMockSimFacilityLock(parser.nextText());
742                             Log.d(
743                                     mTag,
744                                     "Found "
745                                             + MOCK_FACILITY_LOCK_FD_TAG
746                                             + ": fd lock = "
747                                             + fd_lock);
748                         } else if (mocksim_validation
749                                 && mocksim_pf_validatiion
750                                 && MOCK_FACILITY_LOCK_SC_TAG.equals(parser.getName())) {
751                             sc_lock = convertMockSimFacilityLock(parser.nextText());
752                             Log.d(
753                                     mTag,
754                                     "Found "
755                                             + MOCK_FACILITY_LOCK_SC_TAG
756                                             + ": sc lock = "
757                                             + sc_lock);
758                         } else if (mocksim_validation
759                                 && mocksim_pf_validatiion
760                                 && MOCK_MF_TAG.equals(parser.getName())) {
761                             SimAppData simAppData;
762                             String name = parser.getAttributeValue(0);
763                             String path = parser.getAttributeValue(1);
764                             simAppData = new SimAppData(appidx, name, path);
765                             if (simAppData == null) {
766                                 Log.e(mTag, "Create SIM app data failed!");
767                                 result = false;
768                                 break;
769                             }
770                             mSimAppList.add(simAppData);
771                             Log.d(
772                                     mTag,
773                                     "Found "
774                                             + MOCK_MF_TAG
775                                             + ": name = "
776                                             + name
777                                             + " path = "
778                                             + path);
779                         } else if (mocksim_validation
780                                 && mocksim_pf_validatiion
781                                 && !mocksim_mf_validation
782                                 && MOCK_EF_DIR_TAG.equals(parser.getName())) {
783                             SimAppData simAppData;
784                             String name = parser.getAttributeValue(0);
785                             boolean curr_active = Boolean.parseBoolean(parser.getAttributeValue(1));
786                             String aid = parser.nextText();
787                             simAppData = new SimAppData(appidx, aid, name, curr_active);
788                             if (simAppData == null) {
789                                 Log.e(mTag, "Create SIM app data failed!");
790                                 result = false;
791                                 break;
792                             }
793                             simAppData.setFdnStatus(fd_lock);
794                             simAppData.setPin1State(sc_lock);
795                             mSimAppList.add(simAppData);
796                             if (curr_active) {
797                                 mSimApp[appidx].aidPtr = aid;
798                             }
799                             Log.d(
800                                     mTag,
801                                     "Found "
802                                             + MOCK_EF_DIR_TAG
803                                             + ": name = "
804                                             + name
805                                             + ": curr_active = "
806                                             + curr_active
807                                             + " aid = "
808                                             + aid);
809                             mocksim_mf_validation = true;
810                         } else if (mocksim_validation
811                                 && mocksim_pf_validatiion
812                                 && mocksim_mf_validation
813                                 && MOCK_ADF_TAG.equals(parser.getName())) {
814                             String aid = parser.getAttributeValue(0);
815                             Log.d(mTag, "Found " + MOCK_ADF_TAG + ": aid = " + aid);
816                             adf_aid = aid;
817                         } else if (mocksim_validation
818                                 && mocksim_pf_validatiion
819                                 && mocksim_mf_validation
820                                 && (adf_aid.length() > 0)
821                                 && MOCK_EF_TAG.equals(parser.getName())) {
822                             String name = parser.getAttributeValue(0);
823                             String id = parser.getAttributeValue(1);
824                             String command = parser.getAttributeValue(2);
825                             String[] value;
826                             switch (id) {
827                                 case "6F07": // EF_IMSI
828                                     int mncDigit = Integer.parseInt(parser.getAttributeValue(3));
829                                     String imsi = parser.nextText();
830                                     value = extractImsi(imsi, mncDigit);
831                                     if (value != null
832                                             && storeEfData(adf_aid, name, id, command, value)) {
833                                         Log.d(
834                                                 mTag,
835                                                 "Found "
836                                                         + MOCK_EF_TAG
837                                                         + ": name = "
838                                                         + name
839                                                         + " id = "
840                                                         + id
841                                                         + " command = "
842                                                         + command
843                                                         + " value = "
844                                                         + imsi
845                                                         + " with mnc-digit = "
846                                                         + mncDigit);
847                                     }
848                                     break;
849                                 default:
850                                     value = new String[1];
851                                     if (value != null) {
852                                         value[0] = parser.nextText();
853                                         if (storeEfData(adf_aid, name, id, command, value)) {
854                                             Log.d(
855                                                     mTag,
856                                                     "Found "
857                                                             + MOCK_EF_TAG
858                                                             + ": name = "
859                                                             + name
860                                                             + " id = "
861                                                             + id
862                                                             + " command = "
863                                                             + command
864                                                             + " value = "
865                                                             + value[0]);
866                                         }
867                                     }
868                                     break;
869                             }
870                         }
871                         break;
872                     case XmlPullParser.END_TAG:
873                         if (mocksim_validation && MOCK_SIM_PROFILE_TAG.equals(parser.getName())) {
874                             appidx++;
875                             mocksim_pf_validatiion = false;
876                             mocksim_mf_validation = false;
877                         } else if (mocksim_validation && MOCK_ADF_TAG.equals(parser.getName())) {
878                             adf_aid = "";
879                         }
880                         break;
881                 }
882             }
883             Log.d(mTag, "Totally create " + Math.min(mSimApp.length, appidx) + " SIM profiles");
884             mSimProfileInfoList[mSimProfileId].setNumOfSimApp(appidx);
885             input.close();
886         } catch (Exception e) {
887             Log.e(mTag, "Exception error: " + e);
888             result = false;
889         }
890 
891         return result;
892     }
893 
loadSimApp()894     private boolean loadSimApp() {
895         boolean result = true;
896 
897         if (mSimAppList == null) {
898             mSimAppList = new ArrayList<SimAppData>();
899         } else {
900             mSimAppList.clear();
901         }
902 
903         if (mSimProfileId == MOCK_SIM_PROFILE_ID_DEFAULT
904                 || mSimProfileInfoList[mSimProfileId].getXmlFile().length() == 0) {
905             Log.d(mTag, "SIM absent case");
906             mSimApp = new AppStatus[0];
907             if (mSimApp == null) {
908                 Log.e(mTag, "Create SIM app failed!");
909                 result = false;
910             }
911         } else {
912             result = loadSimProfileFromXml();
913         }
914 
915         return result;
916     }
917 
loadMockSimCard()918     private boolean loadMockSimCard() {
919         if (mSimProfileId != MOCK_SIM_PROFILE_ID_DEFAULT) {
920             switch (mPhysicalSlotId) {
921                 case MOCK_SIM_SLOT_1: // pSIM
922                     mEID = DEFAULT_SIM1_EID;
923                     break;
924                 case MOCK_SIM_SLOT_2: // eSIM
925                     mATR = DEFAULT_SIM2_ATR;
926                     mEID = DEFAULT_SIM2_EID;
927                     break;
928                 case MOCK_SIM_SLOT_3: // eSIM
929                     mATR = DEFAULT_SIM3_ATR;
930                     mEID = DEFAULT_SIM3_EID;
931                     break;
932             }
933             mUniversalPinState = PinState.DISABLED;
934             mIsCardPresent = true;
935         } else {
936             switch (mPhysicalSlotId) {
937                 case MOCK_SIM_SLOT_1:
938                     mATR = DEFAULT_SIM1_ATR;
939                     mEID = DEFAULT_SIM1_EID;
940                     mUniversalPinState = DEFAULT_SIM1_UNIVERSAL_PIN_STATE;
941                     mIsCardPresent = DEFAULT_SIM1_CARD_PRESENT;
942                     break;
943                 case MOCK_SIM_SLOT_2:
944                     mATR = DEFAULT_SIM2_ATR;
945                     mEID = DEFAULT_SIM2_EID;
946                     mUniversalPinState = DEFAULT_SIM2_UNIVERSAL_PIN_STATE;
947                     mIsCardPresent = DEFAULT_SIM2_CARD_PRESENT;
948                     break;
949                 case MOCK_SIM_SLOT_3:
950                     mATR = DEFAULT_SIM3_ATR;
951                     mEID = DEFAULT_SIM3_EID;
952                     mUniversalPinState = DEFAULT_SIM3_UNIVERSAL_PIN_STATE;
953                     mIsCardPresent = DEFAULT_SIM3_CARD_PRESENT;
954                     break;
955             }
956         }
957         return loadSimApp();
958     }
959 
loadSimCard(int simprofileid)960     public boolean loadSimCard(int simprofileid) {
961         boolean result = true;
962         if (mSimProfileId >= MOCK_SIM_PROFILE_ID_DEFAULT
963                 && mSimProfileId < MOCK_SIM_PROFILE_ID_MAX) {
964             mSimProfileId = simprofileid;
965             result = loadMockSimCard();
966         } else {
967             result = false;
968         }
969         return result;
970     }
971 
isSlotPortActive()972     public boolean isSlotPortActive() {
973         return mIsSlotPortActive;
974     }
975 
isCardPresent()976     public boolean isCardPresent() {
977         return mIsCardPresent;
978     }
979 
getNumOfSimPortInfo()980     public int getNumOfSimPortInfo() {
981         // TODO: support multiple sim port
982         return DEFAULT_NUM_OF_SIM_PORT_INFO;
983     }
984 
getPhysicalSlotId()985     public int getPhysicalSlotId() {
986         return mPhysicalSlotId;
987     }
988 
getLogicalSlotId()989     public int getLogicalSlotId() {
990         return mLogicalSlotId;
991     }
992 
getSlotPortId()993     public int getSlotPortId() {
994         return mSlotPortId;
995     }
996 
getEID()997     public String getEID() {
998         return mEID;
999     }
1000 
setATR(String atr)1001     public boolean setATR(String atr) {
1002         // TODO: add any ATR format check
1003         mATR = atr;
1004         return true;
1005     }
1006 
getATR()1007     public String getATR() {
1008         return mATR;
1009     }
1010 
setICCID(String iccid)1011     public boolean setICCID(String iccid) {
1012         boolean result = false;
1013         SimAppData activeSimAppData = getActiveSimAppData();
1014 
1015         // TODO: add iccid format check
1016         if (activeSimAppData != null) {
1017             String iccidInfo = activeSimAppData.getIccidInfo();
1018             int dataFileSize = iccid.length() / 2;
1019             String dataFileSizeStr = Integer.toString(dataFileSize, 16);
1020 
1021             Log.d(mTag, "Data file size = " + dataFileSizeStr);
1022             if (dataFileSizeStr.length() <= 4) {
1023                 dataFileSizeStr = String.format("%04x", dataFileSize).toUpperCase(Locale.ROOT);
1024                 // Data file size index is 2 and 3 in byte array of iccid info data.
1025                 iccidInfo = iccidInfo.substring(0, 4) + dataFileSizeStr + iccidInfo.substring(8);
1026                 Log.d(mTag, "Update iccid info = " + iccidInfo);
1027                 activeSimAppData.setIccidInfo(iccidInfo);
1028                 activeSimAppData.setIccid(iccid);
1029                 result = true;
1030             } else {
1031                 Log.e(mTag, "Data file size(" + iccidInfo.length() + ") is too large.");
1032             }
1033         } else {
1034             Log.e(mTag, "activeSimAppData = null");
1035         }
1036 
1037         return result;
1038     }
1039 
getICCID()1040     public String getICCID() {
1041         String iccid = "";
1042         SimAppData activeSimAppData = getActiveSimAppData();
1043 
1044         if (activeSimAppData != null) {
1045             iccid = activeSimAppData.getIccid();
1046         }
1047 
1048         return iccid;
1049     }
1050 
getUniversalPinState()1051     public int getUniversalPinState() {
1052         return mUniversalPinState;
1053     }
1054 
getGsmAppIndex()1055     public int getGsmAppIndex() {
1056         return mSimProfileInfoList[mSimProfileId].getGsmAppIndex();
1057     }
1058 
getCdmaAppIndex()1059     public int getCdmaAppIndex() {
1060         return mSimProfileInfoList[mSimProfileId].getCdmaAppIndex();
1061     }
1062 
getImsAppIndex()1063     public int getImsAppIndex() {
1064         return mSimProfileInfoList[mSimProfileId].getImsAppIndex();
1065     }
1066 
getNumOfSimApp()1067     public int getNumOfSimApp() {
1068         return mSimProfileInfoList[mSimProfileId].getNumOfSimApp();
1069     }
1070 
getSimApp()1071     public AppStatus[] getSimApp() {
1072         return mSimApp;
1073     }
1074 
getSimAppList()1075     public ArrayList<SimAppData> getSimAppList() {
1076         return mSimAppList;
1077     }
1078 
getActiveSimAppData()1079     public SimAppData getActiveSimAppData() {
1080         SimAppData activeSimAppData = null;
1081 
1082         for (int simAppIdx = 0; simAppIdx < mSimAppList.size(); simAppIdx++) {
1083             if (mSimAppList.get(simAppIdx).isCurrentActive()) {
1084                 activeSimAppData = mSimAppList.get(simAppIdx);
1085                 break;
1086             }
1087         }
1088 
1089         return activeSimAppData;
1090     }
1091 
getActiveSimAppId()1092     public String getActiveSimAppId() {
1093         String aid = "";
1094         SimAppData activeSimAppData = getActiveSimAppData();
1095 
1096         if (activeSimAppData != null) {
1097             aid = activeSimAppData.getAid();
1098         }
1099 
1100         return aid;
1101     }
1102 
setMcc(String mcc)1103     private boolean setMcc(String mcc) {
1104         boolean result = false;
1105 
1106         if (mcc.length() == 3) {
1107             SimAppData activeSimAppData = getActiveSimAppData();
1108             if (activeSimAppData != null) {
1109                 activeSimAppData.setMcc(mcc);
1110                 result = true;
1111             }
1112         }
1113 
1114         return result;
1115     }
1116 
setMnc(String mnc)1117     private boolean setMnc(String mnc) {
1118         boolean result = false;
1119 
1120         if (mnc.length() == 2 || mnc.length() == 3) {
1121             SimAppData activeSimAppData = getActiveSimAppData();
1122             if (activeSimAppData != null) {
1123                 activeSimAppData.setMnc(mnc);
1124                 result = true;
1125             }
1126         }
1127 
1128         return result;
1129     }
1130 
getMccMnc()1131     public String getMccMnc() {
1132         String mcc;
1133         String mnc;
1134         String result = "";
1135         SimAppData activeSimAppData = getActiveSimAppData();
1136 
1137         if (activeSimAppData != null) {
1138             mcc = activeSimAppData.getMcc();
1139             mnc = activeSimAppData.getMnc();
1140             if (mcc != null
1141                     && mcc.length() == 3
1142                     && mnc != null
1143                     && (mnc.length() == 2 || mnc.length() == 3)) {
1144                 result = mcc + mnc;
1145             } else {
1146                 Log.e(mTag, "Invalid Mcc or Mnc.");
1147             }
1148         }
1149         return result;
1150     }
1151 
getMsin()1152     public String getMsin() {
1153         String result = "";
1154         SimAppData activeSimAppData = getActiveSimAppData();
1155 
1156         if (activeSimAppData != null) {
1157             result = activeSimAppData.getMsin();
1158             if (result.length() <= 0 || result.length() > 10) {
1159                 Log.e(mTag, "Invalid Msin.");
1160             }
1161         }
1162 
1163         return result;
1164     }
1165 
setImsi(String mcc, String mnc, String msin)1166     public boolean setImsi(String mcc, String mnc, String msin) {
1167         boolean result = false;
1168 
1169         if (msin.length() > 0 && (mcc.length() + mnc.length() + msin.length()) <= 15) {
1170             SimAppData activeSimAppData = getActiveSimAppData();
1171             if (activeSimAppData != null) {
1172                 setMcc(mcc);
1173                 setMnc(mnc);
1174                 activeSimAppData.setMsin(msin);
1175                 result = true;
1176             } else {
1177                 Log.e(mTag, "activeSimAppData = null");
1178             }
1179         } else {
1180             Log.e(mTag, "Invalid IMSI");
1181         }
1182 
1183         return result;
1184     }
1185 
getImsi()1186     public String getImsi() {
1187         String imsi = "";
1188         String mccmnc;
1189         String msin;
1190         SimAppData activeSimAppData = getActiveSimAppData();
1191 
1192         if (activeSimAppData != null) {
1193             mccmnc = getMccMnc();
1194             msin = activeSimAppData.getMsin();
1195             if (mccmnc.length() > 0
1196                     && msin != null
1197                     && msin.length() > 0
1198                     && (mccmnc.length() + msin.length()) <= 15) {
1199                 imsi = mccmnc + msin;
1200             } else {
1201                 Log.e(mTag, "Invalid Imsi.");
1202             }
1203         }
1204         return imsi;
1205     }
1206 }
1207