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