1 /* 2 * Copyright (C) 2008 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 com.android.internal.telephony.uicc; 18 19 import android.annotation.NonNull; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.content.Context; 22 import android.content.res.Resources; 23 import android.os.AsyncResult; 24 import android.os.Build; 25 import android.os.Message; 26 import android.sysprop.TelephonyProperties; 27 import android.telephony.SubscriptionInfo; 28 import android.telephony.SubscriptionManager; 29 import android.text.TextUtils; 30 import android.util.Log; 31 32 import com.android.internal.annotations.VisibleForTesting; 33 import com.android.internal.telephony.CommandsInterface; 34 import com.android.internal.telephony.GsmAlphabet; 35 import com.android.internal.telephony.MccTable; 36 import com.android.internal.telephony.cdma.sms.UserData; 37 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; 38 import com.android.internal.util.BitwiseInputStream; 39 import com.android.telephony.Rlog; 40 41 import java.io.FileDescriptor; 42 import java.io.PrintWriter; 43 import java.util.ArrayList; 44 import java.util.Arrays; 45 import java.util.Locale; 46 47 /** 48 * {@hide} 49 */ 50 public class RuimRecords extends IccRecords { 51 static final String LOG_TAG = "RuimRecords"; 52 private final static int IMSI_MIN_LENGTH = 10; 53 54 private boolean mOtaCommited=false; 55 56 // ***** Instance Variables 57 58 private String mMyMobileNumber; 59 private String mMin2Min1; 60 61 private String mPrlVersion; 62 // From CSIM application 63 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 64 private byte[] mEFpl = null; 65 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 66 private byte[] mEFli = null; 67 boolean mCsimSpnDisplayCondition = false; 68 private String mMdn; 69 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 70 private String mMin; 71 private String mHomeSystemId; 72 private String mHomeNetworkId; 73 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 74 private String mNai; 75 76 @Override toString()77 public String toString() { 78 return "RuimRecords: " + super.toString() 79 + " m_ota_commited" + mOtaCommited 80 + " mMyMobileNumber=" + "xxxx" 81 + " mMin2Min1=" + mMin2Min1 82 + " mPrlVersion=" + mPrlVersion 83 + " mEFpl=" + IccUtils.bytesToHexString(mEFpl) 84 + " mEFli=" + IccUtils.bytesToHexString(mEFli) 85 + " mCsimSpnDisplayCondition=" + mCsimSpnDisplayCondition 86 + " mMdn=" + mMdn 87 + " mMin=" + mMin 88 + " mHomeSystemId=" + mHomeSystemId 89 + " mHomeNetworkId=" + mHomeNetworkId; 90 } 91 92 // ***** Event Constants 93 private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4; 94 private static final int EVENT_GET_ICCID_DONE = 5; 95 private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10; 96 private static final int EVENT_UPDATE_DONE = 14; 97 private static final int EVENT_GET_SST_DONE = 17; 98 private static final int EVENT_GET_ALL_SMS_DONE = 18; 99 private static final int EVENT_MARK_SMS_READ_DONE = 19; 100 101 private static final int EVENT_SMS_ON_RUIM = 21; 102 private static final int EVENT_GET_SMS_DONE = 22; 103 104 private static final int EVENT_APP_LOCKED = 32; 105 private static final int EVENT_APP_NETWORK_LOCKED = 33; 106 RuimRecords(UiccCardApplication app, Context c, CommandsInterface ci)107 public RuimRecords(UiccCardApplication app, Context c, CommandsInterface ci) { 108 super(app, c, ci); 109 110 mAdnCache = new AdnRecordCache(mFh); 111 112 mRecordsRequested = false; // No load request is made till SIM ready 113 mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE; 114 115 // recordsToLoad is set to 0 because no requests are made yet 116 mRecordsToLoad = 0; 117 118 // NOTE the EVENT_SMS_ON_RUIM is not registered 119 120 // Start off by setting empty state 121 resetRecords(); 122 if (DBG) log("RuimRecords X ctor this=" + this); 123 } 124 125 @Override dispose()126 public void dispose() { 127 if (DBG) log("Disposing RuimRecords " + this); 128 resetRecords(); 129 super.dispose(); 130 } 131 132 @Override finalize()133 protected void finalize() { 134 if(DBG) log("RuimRecords finalized"); 135 } 136 resetRecords()137 protected void resetRecords() { 138 mMncLength = UNINITIALIZED; 139 log("setting0 mMncLength" + mMncLength); 140 mIccId = null; 141 mFullIccId = null; 142 143 mAdnCache.reset(); 144 145 // Don't clean up PROPERTY_ICC_OPERATOR_ISO_COUNTRY and 146 // PROPERTY_ICC_OPERATOR_NUMERIC here. Since not all CDMA 147 // devices have RUIM, these properties should keep the original 148 // values, e.g. build time settings, when there is no RUIM but 149 // set new values when RUIM is available and loaded. 150 151 // recordsRequested is set to false indicating that the SIM 152 // read requests made so far are not valid. This is set to 153 // true only when fresh set of read requests are made. 154 mRecordsRequested = false; 155 mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE; 156 mLoaded.set(false); 157 } 158 159 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getMdnNumber()160 public String getMdnNumber() { 161 return mMyMobileNumber; 162 } 163 getCdmaMin()164 public String getCdmaMin() { 165 return mMin2Min1; 166 } 167 168 /** Returns null if RUIM is not yet ready */ getPrlVersion()169 public String getPrlVersion() { 170 return mPrlVersion; 171 } 172 173 @Override 174 /** Returns null if RUIM is not yet ready */ getNAI()175 public String getNAI() { 176 return mNai; 177 } 178 179 @Override setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete)180 public void setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete){ 181 // In CDMA this is Operator/OEM dependent 182 AsyncResult.forMessage((onComplete)).exception = 183 new IccException("setVoiceMailNumber not implemented"); 184 onComplete.sendToTarget(); 185 loge("method setVoiceMailNumber is not implemented"); 186 } 187 188 /** 189 * Called by CCAT Service when REFRESH is received. 190 * @param fileChanged indicates whether any files changed 191 * @param fileList if non-null, a list of EF files that changed 192 */ 193 @Override onRefresh(boolean fileChanged, int[] fileList)194 public void onRefresh(boolean fileChanged, int[] fileList) { 195 if (fileChanged) { 196 // A future optimization would be to inspect fileList and 197 // only reload those files that we care about. For now, 198 // just re-fetch all RUIM records that we cache. 199 fetchRuimRecords(); 200 } 201 } 202 203 /** 204 * Returns the 5 or 6 digit MCC/MNC of the operator that 205 * provided the RUIM card. Returns null of RUIM is not yet ready 206 */ 207 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getRUIMOperatorNumeric()208 public String getRUIMOperatorNumeric() { 209 String imsi = getIMSI(); 210 211 if (imsi == null) { 212 return null; 213 } 214 215 if (mMncLength != UNINITIALIZED && mMncLength != UNKNOWN) { 216 // Length = length of MCC + length of MNC 217 // length of mcc = 3 (3GPP2 C.S0005 - Section 2.3) 218 return imsi.substring(0, 3 + mMncLength); 219 } 220 221 // Guess the MNC length based on the MCC if we don't 222 // have a valid value in ef[ad] 223 224 int mcc = Integer.parseInt(imsi.substring(0, 3)); 225 return imsi.substring(0, 3 + MccTable.smallestDigitsMccForMnc(mcc)); 226 } 227 228 // Refer to ETSI TS 102.221 229 private class EfPlLoaded implements IccRecordLoaded { 230 @Override getEfName()231 public String getEfName() { 232 return "EF_PL"; 233 } 234 235 @Override onRecordLoaded(AsyncResult ar)236 public void onRecordLoaded(AsyncResult ar) { 237 mEFpl = (byte[]) ar.result; 238 if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEFpl)); 239 } 240 } 241 242 // Refer to C.S0065 5.2.26 243 private class EfCsimLiLoaded implements IccRecordLoaded { 244 @Override getEfName()245 public String getEfName() { 246 return "EF_CSIM_LI"; 247 } 248 249 @Override onRecordLoaded(AsyncResult ar)250 public void onRecordLoaded(AsyncResult ar) { 251 mEFli = (byte[]) ar.result; 252 // convert csim efli data to iso 639 format 253 for (int i = 0; i < mEFli.length; i+=2) { 254 switch(mEFli[i+1]) { 255 case 0x01: mEFli[i] = 'e'; mEFli[i+1] = 'n';break; 256 case 0x02: mEFli[i] = 'f'; mEFli[i+1] = 'r';break; 257 case 0x03: mEFli[i] = 'e'; mEFli[i+1] = 's';break; 258 case 0x04: mEFli[i] = 'j'; mEFli[i+1] = 'a';break; 259 case 0x05: mEFli[i] = 'k'; mEFli[i+1] = 'o';break; 260 case 0x06: mEFli[i] = 'z'; mEFli[i+1] = 'h';break; 261 case 0x07: mEFli[i] = 'h'; mEFli[i+1] = 'e';break; 262 default: mEFli[i] = ' '; mEFli[i+1] = ' '; 263 } 264 } 265 266 if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEFli)); 267 } 268 } 269 270 // Refer to C.S0065 5.2.32 271 private class EfCsimSpnLoaded implements IccRecordLoaded { 272 @Override getEfName()273 public String getEfName() { 274 return "EF_CSIM_SPN"; 275 } 276 277 @Override onRecordLoaded(AsyncResult ar)278 public void onRecordLoaded(AsyncResult ar) { 279 byte[] data = (byte[]) ar.result; 280 if (DBG) log("CSIM_SPN=" + 281 IccUtils.bytesToHexString(data)); 282 283 // C.S0065 for EF_SPN decoding 284 mCsimSpnDisplayCondition = ((0x01 & data[0]) != 0); 285 286 int encoding = data[1]; 287 int language = data[2]; 288 byte[] spnData = new byte[32]; 289 int len = ((data.length - 3) < 32) ? (data.length - 3) : 32; 290 System.arraycopy(data, 3, spnData, 0, len); 291 292 int numBytes; 293 for (numBytes = 0; numBytes < spnData.length; numBytes++) { 294 if ((spnData[numBytes] & 0xFF) == 0xFF) break; 295 } 296 297 if (numBytes == 0) { 298 setServiceProviderName(""); 299 return; 300 } 301 try { 302 switch (encoding) { 303 case UserData.ENCODING_OCTET: 304 case UserData.ENCODING_LATIN: 305 setServiceProviderName(new String(spnData, 0, numBytes, "ISO-8859-1")); 306 break; 307 case UserData.ENCODING_IA5: 308 case UserData.ENCODING_GSM_7BIT_ALPHABET: 309 setServiceProviderName( 310 GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes*8)/7)); 311 break; 312 case UserData.ENCODING_7BIT_ASCII: 313 String spn = new String(spnData, 0, numBytes, "US-ASCII"); 314 // To address issues with incorrect encoding scheme 315 // programmed in some commercial CSIM cards, the decoded 316 // SPN is checked to have characters in printable ASCII 317 // range. If not, they are decoded with 318 // ENCODING_GSM_7BIT_ALPHABET scheme. 319 if (isPrintableAsciiOnly(spn)) { 320 setServiceProviderName(spn); 321 } else { 322 if (DBG) log("Some corruption in SPN decoding = " + spn); 323 if (DBG) log("Using ENCODING_GSM_7BIT_ALPHABET scheme..."); 324 setServiceProviderName( 325 GsmAlphabet.gsm7BitPackedToString(spnData, 0, (numBytes * 8) / 7)); 326 } 327 break; 328 case UserData.ENCODING_UNICODE_16: 329 setServiceProviderName(new String(spnData, 0, numBytes, "utf-16")); 330 break; 331 default: 332 log("SPN encoding not supported"); 333 } 334 } catch(Exception e) { 335 log("spn decode error: " + e); 336 } 337 if (DBG) log("spn=" + getServiceProviderName()); 338 if (DBG) log("spnCondition=" + mCsimSpnDisplayCondition); 339 mTelephonyManager.setSimOperatorNameForPhone( 340 mParentApp.getPhoneId(), getServiceProviderName()); 341 } 342 } 343 isPrintableAsciiOnly(final CharSequence str)344 private static boolean isPrintableAsciiOnly(final CharSequence str) { 345 final int len = str.length(); 346 for (int i = 0; i < len; i++) { 347 if (!isPrintableAscii(str.charAt(i))) { 348 return false; 349 } 350 } 351 return true; 352 } 353 isPrintableAscii(final char c)354 private static boolean isPrintableAscii(final char c) { 355 final int asciiFirst = 0x20; 356 final int asciiLast = 0x7E; // included 357 return (asciiFirst <= c && c <= asciiLast) || c == '\r' || c == '\n'; 358 } 359 360 private class EfCsimMdnLoaded implements IccRecordLoaded { 361 @Override getEfName()362 public String getEfName() { 363 return "EF_CSIM_MDN"; 364 } 365 366 @Override onRecordLoaded(AsyncResult ar)367 public void onRecordLoaded(AsyncResult ar) { 368 byte[] data = (byte[]) ar.result; 369 if (DBG) log("CSIM_MDN=" + IccUtils.bytesToHexString(data)); 370 // Refer to C.S0065 5.2.35 371 int mdnDigitsNum = 0x0F & data[0]; 372 mMdn = IccUtils.cdmaBcdToString(data, 1, mdnDigitsNum); 373 if (DBG) log("CSIM MDN=" + mMdn); 374 } 375 } 376 377 /** 378 * Parses IMSI based on C.S0065 section 5.2.2 and C.S0005 section 2.3.1 379 */ 380 @VisibleForTesting 381 public class EfCsimImsimLoaded implements IccRecordLoaded { 382 @Override getEfName()383 public String getEfName() { 384 return "EF_CSIM_IMSIM"; 385 } 386 387 @Override onRecordLoaded(AsyncResult ar)388 public void onRecordLoaded(AsyncResult ar) { 389 byte[] data = (byte[]) ar.result; 390 if (data == null || data.length < IMSI_MIN_LENGTH) { 391 loge("Invalid IMSI from EF_CSIM_IMSIM"); 392 return; 393 } 394 if (DBG) log("data=" + Rlog.pii(LOG_TAG, IccUtils.bytesToHexString(data))); 395 // C.S0065 section 5.2.2 for IMSI_M encoding 396 // C.S0005 section 2.3.1 for MIN encoding in IMSI_M. 397 boolean provisioned = ((data[7] & 0x80) == 0x80); 398 399 if (provisioned) { 400 final String imsi = decodeImsi(data); 401 if (TextUtils.isEmpty(mImsi)) { 402 mImsi = imsi; 403 if (DBG) log("IMSI=" + Rlog.pii(LOG_TAG, mImsi)); 404 } 405 mMin = imsi.substring(5, 15); 406 if (DBG) log("min present=" + Rlog.pii(LOG_TAG, mMin)); 407 } else { 408 if (DBG) log("min not present"); 409 } 410 } 411 decodeImsiDigits(int digits, int length)412 private int decodeImsiDigits(int digits, int length) { 413 // Per C.S0005 section 2.3.1. 414 for (int i = 0, denominator = 1; i < length; i++) { 415 digits += denominator; 416 if ((digits / denominator) % 10 == 0) { 417 digits = digits - (10 * denominator); 418 } 419 denominator *= 10; 420 } 421 return digits; 422 } 423 424 /** 425 * Decode utility to decode IMSI from data read from EF_IMSIM 426 * Please refer to 427 * C.S0065 section 5.2.2 for IMSI_M encoding 428 * C.S0005 section 2.3.1 for MIN encoding in IMSI_M. 429 */ 430 @VisibleForTesting 431 @NonNull decodeImsi(byte[] data)432 public String decodeImsi(byte[] data) { 433 // Retrieve the MCC and digits 11 and 12 434 int mcc_data = ((0x03 & data[9]) << 8) | (0xFF & data[8]); 435 int mcc = decodeImsiDigits(mcc_data, 3); 436 int digits_11_12_data = data[6] & 0x7f; 437 int digits_11_12 = decodeImsiDigits(digits_11_12_data, 2); 438 439 // Retrieve 10 MIN digits 440 int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]); 441 int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6; 442 int digit7 = 0x0F & (data[4] >> 2); 443 if (digit7 > 0x09) digit7 = 0; 444 int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]); 445 446 first3digits = decodeImsiDigits(first3digits, 3); 447 second3digits = decodeImsiDigits(second3digits, 3); 448 last3digits = decodeImsiDigits(last3digits, 3); 449 450 StringBuilder builder = new StringBuilder(); 451 builder.append(String.format(Locale.US, "%03d", mcc)); 452 builder.append(String.format(Locale.US, "%02d", digits_11_12)); 453 builder.append(String.format(Locale.US, "%03d", first3digits)); 454 builder.append(String.format(Locale.US, "%03d", second3digits)); 455 builder.append(String.format(Locale.US, "%d", digit7)); 456 builder.append(String.format(Locale.US, "%03d", last3digits)); 457 return builder.toString(); 458 } 459 } 460 461 private class EfCsimCdmaHomeLoaded implements IccRecordLoaded { 462 @Override getEfName()463 public String getEfName() { 464 return "EF_CSIM_CDMAHOME"; 465 } 466 467 @Override onRecordLoaded(AsyncResult ar)468 public void onRecordLoaded(AsyncResult ar) { 469 // Per C.S0065 section 5.2.8 470 ArrayList<byte[]> dataList = (ArrayList<byte[]>) ar.result; 471 if (DBG) log("CSIM_CDMAHOME data size=" + dataList.size()); 472 if (dataList.isEmpty()) { 473 return; 474 } 475 StringBuilder sidBuf = new StringBuilder(); 476 StringBuilder nidBuf = new StringBuilder(); 477 478 for (byte[] data : dataList) { 479 if (data.length == 5) { 480 int sid = ((data[1] & 0xFF) << 8) | (data[0] & 0xFF); 481 int nid = ((data[3] & 0xFF) << 8) | (data[2] & 0xFF); 482 sidBuf.append(sid).append(','); 483 nidBuf.append(nid).append(','); 484 } 485 } 486 // remove trailing "," 487 sidBuf.setLength(sidBuf.length()-1); 488 nidBuf.setLength(nidBuf.length()-1); 489 490 mHomeSystemId = sidBuf.toString(); 491 mHomeNetworkId = nidBuf.toString(); 492 } 493 } 494 495 private class EfCsimEprlLoaded implements IccRecordLoaded { 496 @Override getEfName()497 public String getEfName() { 498 return "EF_CSIM_EPRL"; 499 } 500 @Override onRecordLoaded(AsyncResult ar)501 public void onRecordLoaded(AsyncResult ar) { 502 onGetCSimEprlDone(ar); 503 } 504 } 505 506 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) onGetCSimEprlDone(AsyncResult ar)507 private void onGetCSimEprlDone(AsyncResult ar) { 508 // C.S0065 section 5.2.57 for EFeprl encoding 509 // C.S0016 section 3.5.5 for PRL format. 510 byte[] data = (byte[]) ar.result; 511 if (DBG) log("CSIM_EPRL=" + IccUtils.bytesToHexString(data)); 512 513 // Only need the first 4 bytes of record 514 if (data.length > 3) { 515 int prlId = ((data[2] & 0xFF) << 8) | (data[3] & 0xFF); 516 mPrlVersion = Integer.toString(prlId); 517 } 518 if (DBG) log("CSIM PRL version=" + mPrlVersion); 519 } 520 521 private class EfCsimMipUppLoaded implements IccRecordLoaded { 522 @Override getEfName()523 public String getEfName() { 524 return "EF_CSIM_MIPUPP"; 525 } 526 checkLengthLegal(int length, int expectLength)527 boolean checkLengthLegal(int length, int expectLength) { 528 if(length < expectLength) { 529 Log.e(LOG_TAG, "CSIM MIPUPP format error, length = " + length + 530 "expected length at least =" + expectLength); 531 return false; 532 } else { 533 return true; 534 } 535 } 536 537 @Override onRecordLoaded(AsyncResult ar)538 public void onRecordLoaded(AsyncResult ar) { 539 // 3GPP2 C.S0065 section 5.2.24 540 byte[] data = (byte[]) ar.result; 541 542 if(data.length < 1) { 543 Log.e(LOG_TAG,"MIPUPP read error"); 544 return; 545 } 546 547 BitwiseInputStream bitStream = new BitwiseInputStream(data); 548 try { 549 int mipUppLength = bitStream.read(8); 550 //transfer length from byte to bit 551 mipUppLength = (mipUppLength << 3); 552 553 if (!checkLengthLegal(mipUppLength, 1)) { 554 return; 555 } 556 //parse the MIPUPP body 3GPP2 C.S0016-C 3.5.8.6 557 int retryInfoInclude = bitStream.read(1); 558 mipUppLength--; 559 560 if(retryInfoInclude == 1) { 561 if (!checkLengthLegal(mipUppLength, 11)) { 562 return; 563 } 564 bitStream.skip(11); //not used now 565 //transfer length from byte to bit 566 mipUppLength -= 11; 567 } 568 569 if (!checkLengthLegal(mipUppLength, 4)) { 570 return; 571 } 572 int numNai = bitStream.read(4); 573 mipUppLength -= 4; 574 575 //start parse NAI body 576 for(int index = 0; index < numNai; index++) { 577 if (!checkLengthLegal(mipUppLength, 4)) { 578 return; 579 } 580 int naiEntryIndex = bitStream.read(4); 581 mipUppLength -= 4; 582 583 if (!checkLengthLegal(mipUppLength, 8)) { 584 return; 585 } 586 int naiLength = bitStream.read(8); 587 mipUppLength -= 8; 588 589 if(naiEntryIndex == 0) { 590 //we find the one! 591 if (!checkLengthLegal(mipUppLength, naiLength << 3)) { 592 return; 593 } 594 char naiCharArray[] = new char[naiLength]; 595 for(int index1 = 0; index1 < naiLength; index1++) { 596 naiCharArray[index1] = (char)(bitStream.read(8) & 0xFF); 597 } 598 mNai = new String(naiCharArray); 599 if (Log.isLoggable(LOG_TAG, Log.VERBOSE)) { 600 Log.v(LOG_TAG,"MIPUPP Nai = " + mNai); 601 } 602 return; //need not parsing further 603 } else { 604 //ignore this NAI body 605 if (!checkLengthLegal(mipUppLength, (naiLength << 3) + 102)) { 606 return; 607 } 608 bitStream.skip((naiLength << 3) + 101);//not used 609 int mnAaaSpiIndicator = bitStream.read(1); 610 mipUppLength -= ((naiLength << 3) + 102); 611 612 if(mnAaaSpiIndicator == 1) { 613 if (!checkLengthLegal(mipUppLength, 32)) { 614 return; 615 } 616 bitStream.skip(32); //not used 617 mipUppLength -= 32; 618 } 619 620 //MN-HA_AUTH_ALGORITHM 621 if (!checkLengthLegal(mipUppLength, 5)) { 622 return; 623 } 624 bitStream.skip(4); 625 mipUppLength -= 4; 626 int mnHaSpiIndicator = bitStream.read(1); 627 mipUppLength--; 628 629 if(mnHaSpiIndicator == 1) { 630 if (!checkLengthLegal(mipUppLength, 32)) { 631 return; 632 } 633 bitStream.skip(32); 634 mipUppLength -= 32; 635 } 636 } 637 } 638 } catch(Exception e) { 639 Log.e(LOG_TAG,"MIPUPP read Exception error!"); 640 return; 641 } 642 } 643 } 644 645 @Override handleMessage(Message msg)646 public void handleMessage(Message msg) { 647 AsyncResult ar; 648 649 byte data[]; 650 651 boolean isRecordLoadResponse = false; 652 653 if (mDestroyed.get()) { 654 loge("Received message " + msg + 655 "[" + msg.what + "] while being destroyed. Ignoring."); 656 return; 657 } 658 659 try { 660 switch (msg.what) { 661 case EVENT_GET_DEVICE_IDENTITY_DONE: 662 log("Event EVENT_GET_DEVICE_IDENTITY_DONE Received"); 663 break; 664 665 case EVENT_GET_CDMA_SUBSCRIPTION_DONE: 666 ar = (AsyncResult)msg.obj; 667 String localTemp[] = (String[])ar.result; 668 if (ar.exception != null) { 669 break; 670 } 671 672 mMyMobileNumber = localTemp[0]; 673 mMin2Min1 = localTemp[3]; 674 mPrlVersion = localTemp[4]; 675 676 log("MDN: " + mMyMobileNumber + " MIN: " + mMin2Min1); 677 678 break; 679 680 case EVENT_GET_ICCID_DONE: 681 isRecordLoadResponse = true; 682 683 ar = (AsyncResult)msg.obj; 684 data = (byte[])ar.result; 685 686 if (ar.exception != null) { 687 break; 688 } 689 690 mIccId = IccUtils.bcdToString(data, 0, data.length); 691 mFullIccId = IccUtils.bchToString(data, 0, data.length); 692 693 log("iccid: " + SubscriptionInfo.getPrintableId(mFullIccId)); 694 695 break; 696 697 case EVENT_UPDATE_DONE: 698 ar = (AsyncResult)msg.obj; 699 if (ar.exception != null) { 700 Rlog.i(LOG_TAG, "RuimRecords update failed", ar.exception); 701 } 702 break; 703 704 case EVENT_GET_ALL_SMS_DONE: 705 case EVENT_MARK_SMS_READ_DONE: 706 case EVENT_SMS_ON_RUIM: 707 case EVENT_GET_SMS_DONE: 708 Rlog.w(LOG_TAG, "Event not supported: " + msg.what); 709 break; 710 711 // TODO: probably EF_CST should be read instead 712 case EVENT_GET_SST_DONE: 713 log("Event EVENT_GET_SST_DONE Received"); 714 break; 715 716 default: 717 super.handleMessage(msg); // IccRecords handles generic record load responses 718 719 }}catch (RuntimeException exc) { 720 // I don't want these exceptions to be fatal 721 Rlog.w(LOG_TAG, "Exception parsing RUIM record", exc); 722 } finally { 723 // Count up record load responses even if they are fails 724 if (isRecordLoadResponse) { 725 onRecordLoaded(); 726 } 727 } 728 } 729 730 /** 731 * Returns an array of languages we have assets for. 732 * 733 * NOTE: This array will have duplicates. If this method will be caused 734 * frequently or in a tight loop, it can be rewritten for efficiency. 735 */ 736 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getAssetLanguages(Context ctx)737 private static String[] getAssetLanguages(Context ctx) { 738 final String[] locales = ctx.getAssets().getLocales(); 739 final String[] localeLangs = new String[locales.length]; 740 for (int i = 0; i < locales.length; ++i) { 741 final String localeStr = locales[i]; 742 final int separator = localeStr.indexOf('-'); 743 if (separator < 0) { 744 localeLangs[i] = localeStr; 745 } else { 746 localeLangs[i] = localeStr.substring(0, separator); 747 } 748 } 749 750 return localeLangs; 751 } 752 753 @Override onRecordLoaded()754 protected void onRecordLoaded() { 755 // One record loaded successfully or failed, In either case 756 // we need to update the recordsToLoad count 757 mRecordsToLoad -= 1; 758 if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); 759 760 if (getRecordsLoaded()) { 761 onAllRecordsLoaded(); 762 } else if (getLockedRecordsLoaded() || getNetworkLockedRecordsLoaded()) { 763 onLockedAllRecordsLoaded(); 764 } else if (mRecordsToLoad < 0) { 765 loge("recordsToLoad <0, programmer error suspected"); 766 mRecordsToLoad = 0; 767 } 768 } 769 onLockedAllRecordsLoaded()770 private void onLockedAllRecordsLoaded() { 771 if (mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED) { 772 mLockedRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); 773 } else if (mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED) { 774 mNetworkLockedRecordsLoadedRegistrants.notifyRegistrants( 775 new AsyncResult(null, null, null)); 776 } else { 777 loge("onLockedAllRecordsLoaded: unexpected mLockedRecordsReqReason " 778 + mLockedRecordsReqReason); 779 } 780 } 781 782 @Override onAllRecordsLoaded()783 protected void onAllRecordsLoaded() { 784 if (DBG) log("record load complete"); 785 786 // Further records that can be inserted are Operator/OEM dependent 787 788 // FIXME: CSIM IMSI may not contain the MNC. 789 if (false) { 790 String operator = getRUIMOperatorNumeric(); 791 if (!TextUtils.isEmpty(operator)) { 792 log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + 793 operator + "'"); 794 log("update icc_operator_numeric=" + operator); 795 mTelephonyManager.setSimOperatorNumericForPhone( 796 mParentApp.getPhoneId(), operator); 797 } else { 798 log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); 799 } 800 801 String imsi = getIMSI(); 802 803 if (!TextUtils.isEmpty(imsi)) { 804 log("onAllRecordsLoaded set mcc imsi=" + (VDBG ? ("=" + imsi) : "")); 805 mTelephonyManager.setSimCountryIsoForPhone(mParentApp.getPhoneId(), 806 MccTable.countryCodeForMcc(imsi.substring(0, 3))); 807 } else { 808 log("onAllRecordsLoaded empty imsi skipping setting mcc"); 809 } 810 } 811 812 Resources resource = Resources.getSystem(); 813 if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) { 814 setSimLanguage(mEFli, mEFpl); 815 } 816 817 mLoaded.set(true); 818 mRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); 819 820 if (!TextUtils.isEmpty(mMdn)) { 821 int phoneId = mParentApp.getUiccProfile().getPhoneId(); 822 int subId = SubscriptionManager.getSubscriptionId(phoneId); 823 if (SubscriptionManager.isValidSubscriptionId(subId)) { 824 SubscriptionManager.from(mContext).setDisplayNumber(mMdn, subId); 825 } else { 826 log("Cannot call setDisplayNumber: invalid subId"); 827 } 828 } 829 } 830 831 @Override onReady()832 public void onReady() { 833 fetchRuimRecords(); 834 835 mCi.getCDMASubscription(obtainMessage(EVENT_GET_CDMA_SUBSCRIPTION_DONE)); 836 } 837 838 @Override onLocked()839 protected void onLocked() { 840 if (DBG) log("only fetch EF_ICCID in locked state"); 841 super.onLocked(); 842 843 mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); 844 mRecordsToLoad++; 845 } 846 847 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) fetchRuimRecords()848 private void fetchRuimRecords() { 849 mRecordsRequested = true; 850 851 if (DBG) log("fetchRuimRecords " + mRecordsToLoad); 852 853 mFh.loadEFTransparent(EF_ICCID, 854 obtainMessage(EVENT_GET_ICCID_DONE)); 855 mRecordsToLoad++; 856 857 mFh.loadEFTransparent(EF_PL, 858 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded())); 859 mRecordsToLoad++; 860 861 mFh.loadEFTransparent(EF_CSIM_LI, 862 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimLiLoaded())); 863 mRecordsToLoad++; 864 865 mFh.loadEFTransparent(EF_CSIM_SPN, 866 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimSpnLoaded())); 867 mRecordsToLoad++; 868 869 mFh.loadEFLinearFixed(EF_CSIM_MDN, 1, 870 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMdnLoaded())); 871 mRecordsToLoad++; 872 873 mFh.loadEFTransparent(EF_CSIM_IMSIM, 874 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimImsimLoaded())); 875 mRecordsToLoad++; 876 877 mFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME, 878 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimCdmaHomeLoaded())); 879 mRecordsToLoad++; 880 881 // Entire PRL could be huge. We are only interested in 882 // the first 4 bytes of the record. 883 mFh.loadEFTransparent(EF_CSIM_EPRL, 4, 884 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimEprlLoaded())); 885 mRecordsToLoad++; 886 887 mFh.loadEFTransparent(EF_CSIM_MIPUPP, 888 obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMipUppLoaded())); 889 mRecordsToLoad++; 890 mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE)); 891 mRecordsToLoad++; 892 893 if (DBG) log("fetchRuimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested); 894 // Further records that can be inserted are Operator/OEM dependent 895 } 896 897 @Override isProvisioned()898 public boolean isProvisioned() { 899 // If UICC card has CSIM app, look for MDN and MIN field 900 // to determine if the SIM is provisioned. Otherwise, 901 // consider the SIM is provisioned. (for case of ordinal 902 // USIM only UICC.) 903 // If test_csim is true, bypess provision check and 904 // consider the SIM is provisioned. 905 if (TelephonyProperties.test_csim().orElse(false)) { 906 return true; 907 } 908 909 if (mParentApp == null) { 910 return false; 911 } 912 913 if (mParentApp.getType() == AppType.APPTYPE_CSIM && 914 ((mMdn == null) || (mMin == null))) { 915 return false; 916 } 917 return true; 918 } 919 920 @Override setVoiceMessageWaiting(int line, int countWaiting)921 public void setVoiceMessageWaiting(int line, int countWaiting) { 922 // Will be used in future to store voice mail count in UIM 923 // C.S0023-D_v1.0 does not have a file id in UIM for MWI 924 log("RuimRecords:setVoiceMessageWaiting - NOP for CDMA"); 925 } 926 927 @Override getVoiceMessageCount()928 public int getVoiceMessageCount() { 929 // Will be used in future to retrieve voice mail count for UIM 930 // C.S0023-D_v1.0 does not have a file id in UIM for MWI 931 log("RuimRecords:getVoiceMessageCount - NOP for CDMA"); 932 return 0; 933 } 934 935 @Override handleFileUpdate(int efid)936 protected void handleFileUpdate(int efid) { 937 mLoaded.set(false); 938 mAdnCache.reset(); 939 fetchRuimRecords(); 940 } 941 942 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getMdn()943 public String getMdn() { 944 return mMdn; 945 } 946 getMin()947 public String getMin() { 948 return mMin; 949 } 950 getSid()951 public String getSid() { 952 return mHomeSystemId; 953 } 954 getNid()955 public String getNid() { 956 return mHomeNetworkId; 957 } 958 959 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getCsimSpnDisplayCondition()960 public boolean getCsimSpnDisplayCondition() { 961 return mCsimSpnDisplayCondition; 962 } 963 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 964 @Override log(String s)965 protected void log(String s) { 966 if (mParentApp != null) { 967 Rlog.d(LOG_TAG, "[RuimRecords-" + mParentApp.getPhoneId() + "] " + s); 968 } else { 969 Rlog.d(LOG_TAG, "[RuimRecords] " + s); 970 } 971 } 972 973 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 974 @Override loge(String s)975 protected void loge(String s) { 976 if (mParentApp != null) { 977 Rlog.e(LOG_TAG, "[RuimRecords-" + mParentApp.getPhoneId() + "] " + s); 978 } else { 979 Rlog.e(LOG_TAG, "[RuimRecords] " + s); 980 } 981 } 982 983 @Override dump(FileDescriptor fd, PrintWriter pw, String[] args)984 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 985 pw.println("RuimRecords: " + this); 986 pw.println(" extends:"); 987 super.dump(fd, pw, args); 988 pw.println(" mOtaCommited=" + mOtaCommited); 989 pw.println(" mMyMobileNumber=" + mMyMobileNumber); 990 pw.println(" mMin2Min1=" + mMin2Min1); 991 pw.println(" mPrlVersion=" + mPrlVersion); 992 pw.println(" mEFpl[]=" + Arrays.toString(mEFpl)); 993 pw.println(" mEFli[]=" + Arrays.toString(mEFli)); 994 pw.println(" mCsimSpnDisplayCondition=" + mCsimSpnDisplayCondition); 995 pw.println(" mMdn=" + mMdn); 996 pw.println(" mMin=" + mMin); 997 pw.println(" mHomeSystemId=" + mHomeSystemId); 998 pw.println(" mHomeNetworkId=" + mHomeNetworkId); 999 pw.flush(); 1000 } 1001 } 1002