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