1 /* 2 * Copyright (C) 2014 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; 18 19 import android.Manifest; 20 import android.annotation.Nullable; 21 import android.app.ActivityManager; 22 import android.app.UserSwitchObserver; 23 import android.content.ContentResolver; 24 import android.content.ContentValues; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.content.SharedPreferences; 28 import android.content.pm.IPackageManager; 29 import android.os.AsyncResult; 30 import android.os.Handler; 31 import android.os.IRemoteCallback; 32 import android.os.Looper; 33 import android.os.Message; 34 import android.os.RemoteException; 35 import android.os.ServiceManager; 36 import android.preference.PreferenceManager; 37 import android.provider.Settings; 38 import android.provider.Settings.Global; 39 import android.provider.Settings.SettingNotFoundException; 40 import android.service.euicc.EuiccProfileInfo; 41 import android.service.euicc.EuiccService; 42 import android.service.euicc.GetEuiccProfileInfoListResult; 43 import android.telephony.CarrierConfigManager; 44 import android.telephony.Rlog; 45 import android.telephony.SubscriptionInfo; 46 import android.telephony.SubscriptionManager; 47 import android.telephony.TelephonyManager; 48 import android.telephony.UiccAccessRule; 49 import android.telephony.euicc.EuiccManager; 50 import android.text.TextUtils; 51 52 import com.android.internal.annotations.VisibleForTesting; 53 import com.android.internal.telephony.euicc.EuiccController; 54 import com.android.internal.telephony.uicc.IccRecords; 55 import com.android.internal.telephony.uicc.IccUtils; 56 57 import java.io.FileDescriptor; 58 import java.io.PrintWriter; 59 import java.util.ArrayList; 60 import java.util.List; 61 62 /** 63 *@hide 64 */ 65 public class SubscriptionInfoUpdater extends Handler { 66 private static final String LOG_TAG = "SubscriptionInfoUpdater"; 67 private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount(); 68 69 private static final int EVENT_INVALID = -1; 70 private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2; 71 private static final int EVENT_SIM_LOADED = 3; 72 private static final int EVENT_SIM_ABSENT = 4; 73 private static final int EVENT_SIM_LOCKED = 5; 74 private static final int EVENT_SIM_IO_ERROR = 6; 75 private static final int EVENT_SIM_UNKNOWN = 7; 76 private static final int EVENT_SIM_RESTRICTED = 8; 77 private static final int EVENT_SIM_NOT_READY = 9; 78 private static final int EVENT_SIM_READY = 10; 79 private static final int EVENT_SIM_IMSI = 11; 80 private static final int EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS = 12; 81 82 private static final String ICCID_STRING_FOR_NO_SIM = ""; 83 /** 84 * int[] sInsertSimState maintains all slots' SIM inserted status currently, 85 * it may contain 4 kinds of values: 86 * SIM_NOT_INSERT : no SIM inserted in slot i now 87 * SIM_CHANGED : a valid SIM insert in slot i and is different SIM from last time 88 * it will later become SIM_NEW or SIM_REPOSITION during update procedure 89 * SIM_NOT_CHANGE : a valid SIM insert in slot i and is the same SIM as last time 90 * SIM_NEW : a valid SIM insert in slot i and is a new SIM 91 * SIM_REPOSITION : a valid SIM insert in slot i and is inserted in different slot last time 92 * positive integer #: index to distinguish SIM cards with the same IccId 93 */ 94 public static final int SIM_NOT_CHANGE = 0; 95 public static final int SIM_CHANGED = -1; 96 public static final int SIM_NEW = -2; 97 public static final int SIM_REPOSITION = -3; 98 public static final int SIM_NOT_INSERT = -99; 99 100 public static final int STATUS_NO_SIM_INSERTED = 0x00; 101 public static final int STATUS_SIM1_INSERTED = 0x01; 102 public static final int STATUS_SIM2_INSERTED = 0x02; 103 public static final int STATUS_SIM3_INSERTED = 0x04; 104 public static final int STATUS_SIM4_INSERTED = 0x08; 105 106 // Key used to read/write the current IMSI. Updated on SIM_STATE_CHANGED - LOADED. 107 public static final String CURR_SUBID = "curr_subid"; 108 109 private static Phone[] mPhone; 110 private static Context mContext = null; 111 private static String mIccId[] = new String[PROJECT_SIM_NUM]; 112 private static int[] mInsertSimState = new int[PROJECT_SIM_NUM]; 113 private static int[] sSimCardState = new int[PROJECT_SIM_NUM]; 114 private static int[] sSimApplicationState = new int[PROJECT_SIM_NUM]; 115 private SubscriptionManager mSubscriptionManager = null; 116 private EuiccManager mEuiccManager; 117 private IPackageManager mPackageManager; 118 119 // The current foreground user ID. 120 private int mCurrentlyActiveUserId; 121 private CarrierServiceBindHelper mCarrierServiceBindHelper; 122 SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci)123 public SubscriptionInfoUpdater( 124 Looper looper, Context context, Phone[] phone, CommandsInterface[] ci) { 125 super(looper); 126 logd("Constructor invoked"); 127 128 mContext = context; 129 mPhone = phone; 130 mSubscriptionManager = SubscriptionManager.from(mContext); 131 mEuiccManager = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE); 132 mPackageManager = IPackageManager.Stub.asInterface(ServiceManager.getService("package")); 133 134 mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); 135 initializeCarrierApps(); 136 } 137 initializeCarrierApps()138 private void initializeCarrierApps() { 139 // Initialize carrier apps: 140 // -Now (on system startup) 141 // -Whenever new carrier privilege rules might change (new SIM is loaded) 142 // -Whenever we switch to a new user 143 mCurrentlyActiveUserId = 0; 144 try { 145 ActivityManager.getService().registerUserSwitchObserver(new UserSwitchObserver() { 146 @Override 147 public void onUserSwitching(int newUserId, IRemoteCallback reply) 148 throws RemoteException { 149 mCurrentlyActiveUserId = newUserId; 150 CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), 151 mPackageManager, TelephonyManager.getDefault(), 152 mContext.getContentResolver(), mCurrentlyActiveUserId); 153 154 if (reply != null) { 155 try { 156 reply.sendResult(null); 157 } catch (RemoteException e) { 158 } 159 } 160 } 161 }, LOG_TAG); 162 mCurrentlyActiveUserId = ActivityManager.getService().getCurrentUser().id; 163 } catch (RemoteException e) { 164 logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage()); 165 } 166 CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), 167 mPackageManager, TelephonyManager.getDefault(), mContext.getContentResolver(), 168 mCurrentlyActiveUserId); 169 } 170 updateInternalIccState(String simStatus, String reason, int slotId)171 public void updateInternalIccState(String simStatus, String reason, int slotId) { 172 logd("updateInternalIccState to simStatus " + simStatus + " reason " + reason 173 + " slotId " + slotId); 174 int message = internalIccStateToMessage(simStatus); 175 if (message != EVENT_INVALID) { 176 sendMessage(obtainMessage(message, slotId, -1, reason)); 177 } 178 } 179 internalIccStateToMessage(String simStatus)180 private int internalIccStateToMessage(String simStatus) { 181 switch(simStatus) { 182 case IccCardConstants.INTENT_VALUE_ICC_ABSENT: return EVENT_SIM_ABSENT; 183 case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: return EVENT_SIM_UNKNOWN; 184 case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: return EVENT_SIM_IO_ERROR; 185 case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: return EVENT_SIM_RESTRICTED; 186 case IccCardConstants.INTENT_VALUE_ICC_NOT_READY: return EVENT_SIM_NOT_READY; 187 case IccCardConstants.INTENT_VALUE_ICC_LOCKED: return EVENT_SIM_LOCKED; 188 case IccCardConstants.INTENT_VALUE_ICC_LOADED: return EVENT_SIM_LOADED; 189 case IccCardConstants.INTENT_VALUE_ICC_READY: return EVENT_SIM_READY; 190 case IccCardConstants.INTENT_VALUE_ICC_IMSI: return EVENT_SIM_IMSI; 191 default: 192 logd("Ignoring simStatus: " + simStatus); 193 return EVENT_INVALID; 194 } 195 } 196 isAllIccIdQueryDone()197 private boolean isAllIccIdQueryDone() { 198 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 199 if (mIccId[i] == null) { 200 logd("Wait for SIM" + (i + 1) + " IccId"); 201 return false; 202 } 203 } 204 logd("All IccIds query complete"); 205 206 return true; 207 } 208 209 @Override handleMessage(Message msg)210 public void handleMessage(Message msg) { 211 switch (msg.what) { 212 case EVENT_GET_NETWORK_SELECTION_MODE_DONE: { 213 AsyncResult ar = (AsyncResult)msg.obj; 214 Integer slotId = (Integer)ar.userObj; 215 if (ar.exception == null && ar.result != null) { 216 int[] modes = (int[])ar.result; 217 if (modes[0] == 1) { // Manual mode. 218 mPhone[slotId].setNetworkSelectionModeAutomatic(null); 219 } 220 } else { 221 logd("EVENT_GET_NETWORK_SELECTION_MODE_DONE: error getting network mode."); 222 } 223 break; 224 } 225 226 case EVENT_SIM_LOADED: 227 handleSimLoaded(msg.arg1); 228 break; 229 230 case EVENT_SIM_ABSENT: 231 handleSimAbsent(msg.arg1); 232 break; 233 234 case EVENT_SIM_LOCKED: 235 handleSimLocked(msg.arg1, (String) msg.obj); 236 break; 237 238 case EVENT_SIM_UNKNOWN: 239 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN); 240 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null); 241 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN); 242 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN); 243 break; 244 245 case EVENT_SIM_IO_ERROR: 246 handleSimError(msg.arg1); 247 break; 248 249 case EVENT_SIM_RESTRICTED: 250 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); 251 broadcastSimStateChanged(msg.arg1, 252 IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED, 253 IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); 254 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_CARD_RESTRICTED); 255 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); 256 break; 257 258 case EVENT_SIM_READY: 259 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null); 260 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT); 261 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); 262 break; 263 264 case EVENT_SIM_IMSI: 265 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_IMSI, null); 266 break; 267 268 case EVENT_SIM_NOT_READY: 269 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_NOT_READY, 270 null); 271 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT); 272 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); 273 // intentional fall through 274 // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this 275 // phase, the subscription list is accessible. 276 // TODO(b/64216093): Clean up this special case, likely by treating NOT_READY 277 // as equivalent to ABSENT, once the rest of the system can handle it. Currently 278 // this breaks SystemUI which shows a "No SIM" icon. 279 280 case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS: 281 if (updateEmbeddedSubscriptions()) { 282 SubscriptionController.getInstance().notifySubscriptionInfoChanged(); 283 } 284 if (msg.obj != null) { 285 ((Runnable) msg.obj).run(); 286 } 287 break; 288 289 default: 290 logd("Unknown msg:" + msg.what); 291 } 292 } 293 requestEmbeddedSubscriptionInfoListRefresh(@ullable Runnable callback)294 void requestEmbeddedSubscriptionInfoListRefresh(@Nullable Runnable callback) { 295 sendMessage(obtainMessage(EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, callback)); 296 } 297 handleSimLocked(int slotId, String reason)298 private void handleSimLocked(int slotId, String reason) { 299 if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) { 300 logd("SIM" + (slotId + 1) + " hot plug in"); 301 mIccId[slotId] = null; 302 } 303 304 String iccId = mIccId[slotId]; 305 if (iccId == null) { 306 IccCard iccCard = mPhone[slotId].getIccCard(); 307 if (iccCard == null) { 308 logd("handleSimLocked: IccCard null"); 309 return; 310 } 311 IccRecords records = iccCard.getIccRecords(); 312 if (records == null) { 313 logd("handleSimLocked: IccRecords null"); 314 return; 315 } 316 if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) { 317 logd("handleSimLocked: IccID null"); 318 return; 319 } 320 mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId()); 321 } else { 322 logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId); 323 } 324 325 if (isAllIccIdQueryDone()) { 326 updateSubscriptionInfoByIccId(); 327 } 328 329 updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED); 330 broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason); 331 broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT); 332 broadcastSimApplicationStateChanged(slotId, getSimStateFromLockedReason(reason)); 333 } 334 getSimStateFromLockedReason(String lockedReason)335 private static int getSimStateFromLockedReason(String lockedReason) { 336 switch (lockedReason) { 337 case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN: 338 return TelephonyManager.SIM_STATE_PIN_REQUIRED; 339 case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK: 340 return TelephonyManager.SIM_STATE_PUK_REQUIRED; 341 case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK: 342 return TelephonyManager.SIM_STATE_NETWORK_LOCKED; 343 case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED: 344 return TelephonyManager.SIM_STATE_PERM_DISABLED; 345 default: 346 Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason); 347 return TelephonyManager.SIM_STATE_UNKNOWN; 348 } 349 } 350 handleSimLoaded(int slotId)351 private void handleSimLoaded(int slotId) { 352 logd("handleSimLoaded: slotId: " + slotId); 353 354 // The SIM should be loaded at this state, but it is possible in cases such as SIM being 355 // removed or a refresh RESET that the IccRecords could be null. The right behavior is to 356 // not broadcast the SIM loaded. 357 int loadedSlotId = slotId; 358 IccCard iccCard = mPhone[slotId].getIccCard(); 359 if (iccCard == null) { // Possibly a race condition. 360 logd("handleSimLoaded: IccCard null"); 361 return; 362 } 363 IccRecords records = iccCard.getIccRecords(); 364 if (records == null) { // Possibly a race condition. 365 logd("handleSimLoaded: IccRecords null"); 366 return; 367 } 368 if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) { 369 logd("handleSimLoaded: IccID null"); 370 return; 371 } 372 mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId()); 373 374 if (isAllIccIdQueryDone()) { 375 updateSubscriptionInfoByIccId(); 376 int[] subIds = mSubscriptionManager.getActiveSubscriptionIdList(); 377 for (int subId : subIds) { 378 TelephonyManager tm = TelephonyManager.getDefault(); 379 380 String operator = tm.getSimOperatorNumeric(subId); 381 slotId = SubscriptionController.getInstance().getPhoneId(subId); 382 383 if (!TextUtils.isEmpty(operator)) { 384 if (subId == SubscriptionController.getInstance().getDefaultSubId()) { 385 MccTable.updateMccMncConfiguration(mContext, operator, false); 386 } 387 SubscriptionController.getInstance().setMccMnc(operator, subId); 388 } else { 389 logd("EVENT_RECORDS_LOADED Operator name is null"); 390 } 391 392 String msisdn = tm.getLine1Number(subId); 393 ContentResolver contentResolver = mContext.getContentResolver(); 394 395 if (msisdn != null) { 396 SubscriptionController.getInstance().setDisplayNumber(msisdn, subId); 397 } 398 399 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId); 400 String nameToSet; 401 String simCarrierName = tm.getSimOperatorName(subId); 402 403 if (subInfo != null && subInfo.getNameSource() != 404 SubscriptionManager.NAME_SOURCE_USER_INPUT) { 405 if (!TextUtils.isEmpty(simCarrierName)) { 406 nameToSet = simCarrierName; 407 } else { 408 nameToSet = "CARD " + Integer.toString(slotId + 1); 409 } 410 logd("sim name = " + nameToSet); 411 SubscriptionController.getInstance().setDisplayName(nameToSet, subId); 412 } 413 414 /* Update preferred network type and network selection mode on SIM change. 415 * Storing last subId in SharedPreference for now to detect SIM change. */ 416 SharedPreferences sp = 417 PreferenceManager.getDefaultSharedPreferences(mContext); 418 int storedSubId = sp.getInt(CURR_SUBID + slotId, -1); 419 420 if (storedSubId != subId) { 421 int networkType = Settings.Global.getInt( 422 mPhone[slotId].getContext().getContentResolver(), 423 Settings.Global.PREFERRED_NETWORK_MODE + subId, 424 -1 /* invalid network mode */); 425 426 if (networkType == -1) { 427 networkType = RILConstants.PREFERRED_NETWORK_MODE; 428 try { 429 networkType = TelephonyManager.getIntAtIndex( 430 mContext.getContentResolver(), 431 Settings.Global.PREFERRED_NETWORK_MODE, slotId); 432 } catch (SettingNotFoundException retrySnfe) { 433 Rlog.e(LOG_TAG, "Settings Exception Reading Value At Index for " 434 + "Settings.Global.PREFERRED_NETWORK_MODE"); 435 } 436 Settings.Global.putInt( 437 mPhone[slotId].getContext().getContentResolver(), 438 Global.PREFERRED_NETWORK_MODE + subId, 439 networkType); 440 } 441 442 // Set the modem network mode 443 mPhone[slotId].setPreferredNetworkType(networkType, null); 444 445 // Only support automatic selection mode on SIM change. 446 mPhone[slotId].getNetworkSelectionMode( 447 obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE, 448 new Integer(slotId))); 449 450 // Update stored subId 451 SharedPreferences.Editor editor = sp.edit(); 452 editor.putInt(CURR_SUBID + slotId, subId); 453 editor.apply(); 454 } 455 } 456 } 457 458 // Update set of enabled carrier apps now that the privilege rules may have changed. 459 CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), 460 mPackageManager, TelephonyManager.getDefault(), 461 mContext.getContentResolver(), mCurrentlyActiveUserId); 462 463 broadcastSimStateChanged(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null); 464 broadcastSimCardStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_PRESENT); 465 broadcastSimApplicationStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_LOADED); 466 updateCarrierServices(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED); 467 } 468 updateCarrierServices(int slotId, String simState)469 private void updateCarrierServices(int slotId, String simState) { 470 CarrierConfigManager configManager = (CarrierConfigManager) 471 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 472 configManager.updateConfigForPhoneId(slotId, simState); 473 mCarrierServiceBindHelper.updateForPhoneId(slotId, simState); 474 } 475 handleSimAbsent(int slotId)476 private void handleSimAbsent(int slotId) { 477 if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) { 478 logd("SIM" + (slotId + 1) + " hot plug out"); 479 } 480 mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; 481 if (isAllIccIdQueryDone()) { 482 updateSubscriptionInfoByIccId(); 483 } 484 updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT); 485 broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT, null); 486 broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_ABSENT); 487 broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY); 488 } 489 handleSimError(int slotId)490 private void handleSimError(int slotId) { 491 if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) { 492 logd("SIM" + (slotId + 1) + " Error "); 493 } 494 mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; 495 if (isAllIccIdQueryDone()) { 496 updateSubscriptionInfoByIccId(); 497 } 498 updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); 499 broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR, 500 IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); 501 broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR); 502 broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY); 503 } 504 505 /** 506 * TODO: Simplify more, as no one is interested in what happened 507 * only what the current list contains. 508 */ updateSubscriptionInfoByIccId()509 synchronized private void updateSubscriptionInfoByIccId() { 510 logd("updateSubscriptionInfoByIccId:+ Start"); 511 512 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 513 mInsertSimState[i] = SIM_NOT_CHANGE; 514 } 515 516 int insertedSimCount = PROJECT_SIM_NUM; 517 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 518 if (ICCID_STRING_FOR_NO_SIM.equals(mIccId[i])) { 519 insertedSimCount--; 520 mInsertSimState[i] = SIM_NOT_INSERT; 521 } 522 } 523 logd("insertedSimCount = " + insertedSimCount); 524 525 // We only clear the slot-to-sub map when one/some SIM was removed. Note this is a 526 // workaround for some race conditions that the empty map was accessed while we are 527 // rebuilding the map. 528 if (SubscriptionController.getInstance().getActiveSubIdList().length > insertedSimCount) { 529 SubscriptionController.getInstance().clearSubInfo(); 530 } 531 532 int index = 0; 533 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 534 if (mInsertSimState[i] == SIM_NOT_INSERT) { 535 continue; 536 } 537 index = 2; 538 for (int j = i + 1; j < PROJECT_SIM_NUM; j++) { 539 if (mInsertSimState[j] == SIM_NOT_CHANGE && mIccId[i].equals(mIccId[j])) { 540 mInsertSimState[i] = 1; 541 mInsertSimState[j] = index; 542 index++; 543 } 544 } 545 } 546 547 ContentResolver contentResolver = mContext.getContentResolver(); 548 String[] oldIccId = new String[PROJECT_SIM_NUM]; 549 String[] decIccId = new String[PROJECT_SIM_NUM]; 550 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 551 oldIccId[i] = null; 552 List<SubscriptionInfo> oldSubInfo = SubscriptionController.getInstance() 553 .getSubInfoUsingSlotIndexPrivileged(i, false); 554 decIccId[i] = IccUtils.getDecimalSubstring(mIccId[i]); 555 if (oldSubInfo != null && oldSubInfo.size() > 0) { 556 oldIccId[i] = oldSubInfo.get(0).getIccId(); 557 logd("updateSubscriptionInfoByIccId: oldSubId = " 558 + oldSubInfo.get(0).getSubscriptionId()); 559 if (mInsertSimState[i] == SIM_NOT_CHANGE && !(mIccId[i].equals(oldIccId[i]) 560 || (decIccId[i] != null && decIccId[i].equals(oldIccId[i])))) { 561 mInsertSimState[i] = SIM_CHANGED; 562 } 563 if (mInsertSimState[i] != SIM_NOT_CHANGE) { 564 ContentValues value = new ContentValues(1); 565 value.put(SubscriptionManager.SIM_SLOT_INDEX, 566 SubscriptionManager.INVALID_SIM_SLOT_INDEX); 567 contentResolver.update(SubscriptionManager.CONTENT_URI, value, 568 SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" 569 + Integer.toString(oldSubInfo.get(0).getSubscriptionId()), null); 570 571 // refresh Cached Active Subscription Info List 572 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList(); 573 } 574 } else { 575 if (mInsertSimState[i] == SIM_NOT_CHANGE) { 576 // no SIM inserted last time, but there is one SIM inserted now 577 mInsertSimState[i] = SIM_CHANGED; 578 } 579 oldIccId[i] = ICCID_STRING_FOR_NO_SIM; 580 logd("updateSubscriptionInfoByIccId: No SIM in slot " + i + " last time"); 581 } 582 } 583 584 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 585 logd("updateSubscriptionInfoByIccId: oldIccId[" + i + "] = " + oldIccId[i] + 586 ", sIccId[" + i + "] = " + mIccId[i]); 587 } 588 589 //check if the inserted SIM is new SIM 590 int nNewCardCount = 0; 591 int nNewSimStatus = 0; 592 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 593 if (mInsertSimState[i] == SIM_NOT_INSERT) { 594 logd("updateSubscriptionInfoByIccId: No SIM inserted in slot " + i + " this time"); 595 } else { 596 if (mInsertSimState[i] > 0) { 597 //some special SIMs may have the same IccIds, add suffix to distinguish them 598 //FIXME: addSubInfoRecord can return an error. 599 mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i] 600 + Integer.toString(mInsertSimState[i]), i); 601 logd("SUB" + (i + 1) + " has invalid IccId"); 602 } else /*if (sInsertSimState[i] != SIM_NOT_INSERT)*/ { 603 logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: " 604 + mIccId[i] + "slot: " + i); 605 mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i], i); 606 } 607 if (isNewSim(mIccId[i], decIccId[i], oldIccId)) { 608 nNewCardCount++; 609 switch (i) { 610 case PhoneConstants.SUB1: 611 nNewSimStatus |= STATUS_SIM1_INSERTED; 612 break; 613 case PhoneConstants.SUB2: 614 nNewSimStatus |= STATUS_SIM2_INSERTED; 615 break; 616 case PhoneConstants.SUB3: 617 nNewSimStatus |= STATUS_SIM3_INSERTED; 618 break; 619 //case PhoneConstants.SUB3: 620 // nNewSimStatus |= STATUS_SIM4_INSERTED; 621 // break; 622 } 623 624 mInsertSimState[i] = SIM_NEW; 625 } 626 } 627 } 628 629 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 630 if (mInsertSimState[i] == SIM_CHANGED) { 631 mInsertSimState[i] = SIM_REPOSITION; 632 } 633 logd("updateSubscriptionInfoByIccId: sInsertSimState[" + i + "] = " 634 + mInsertSimState[i]); 635 } 636 637 List<SubscriptionInfo> subInfos = mSubscriptionManager.getActiveSubscriptionInfoList(); 638 int nSubCount = (subInfos == null) ? 0 : subInfos.size(); 639 logd("updateSubscriptionInfoByIccId: nSubCount = " + nSubCount); 640 for (int i=0; i < nSubCount; i++) { 641 SubscriptionInfo temp = subInfos.get(i); 642 643 String msisdn = TelephonyManager.getDefault().getLine1Number( 644 temp.getSubscriptionId()); 645 646 if (msisdn != null) { 647 ContentValues value = new ContentValues(1); 648 value.put(SubscriptionManager.NUMBER, msisdn); 649 contentResolver.update(SubscriptionManager.CONTENT_URI, value, 650 SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" 651 + Integer.toString(temp.getSubscriptionId()), null); 652 653 // refresh Cached Active Subscription Info List 654 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList(); 655 } 656 } 657 658 // Ensure the modems are mapped correctly 659 mSubscriptionManager.setDefaultDataSubId( 660 mSubscriptionManager.getDefaultDataSubscriptionId()); 661 662 // No need to check return value here as we notify for the above changes anyway. 663 updateEmbeddedSubscriptions(); 664 665 SubscriptionController.getInstance().notifySubscriptionInfoChanged(); 666 logd("updateSubscriptionInfoByIccId:- SubscriptionInfo update complete"); 667 } 668 669 /** 670 * Update the cached list of embedded subscriptions. 671 * 672 * @return true if changes may have been made. This is not a guarantee that changes were made, 673 * but notifications about subscription changes may be skipped if this returns false as an 674 * optimization to avoid spurious notifications. 675 */ 676 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) updateEmbeddedSubscriptions()677 public boolean updateEmbeddedSubscriptions() { 678 // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they 679 // are filtered out of list calls as long as EuiccManager.isEnabled returns false). 680 if (!mEuiccManager.isEnabled()) { 681 return false; 682 } 683 684 GetEuiccProfileInfoListResult result = 685 EuiccController.get().blockingGetEuiccProfileInfoList(); 686 if (result == null) { 687 // IPC to the eUICC controller failed. 688 return false; 689 } 690 691 final EuiccProfileInfo[] embeddedProfiles; 692 if (result.getResult() == EuiccService.RESULT_OK) { 693 List<EuiccProfileInfo> list = result.getProfiles(); 694 if (list == null || list.size() == 0) { 695 embeddedProfiles = new EuiccProfileInfo[0]; 696 } else { 697 embeddedProfiles = list.toArray(new EuiccProfileInfo[list.size()]); 698 } 699 } else { 700 logd("updatedEmbeddedSubscriptions: error " + result.getResult() + " listing profiles"); 701 // If there's an error listing profiles, treat it equivalently to a successful 702 // listing which returned no profiles under the assumption that none are currently 703 // accessible. 704 embeddedProfiles = new EuiccProfileInfo[0]; 705 } 706 final boolean isRemovable = result.getIsRemovable(); 707 708 final String[] embeddedIccids = new String[embeddedProfiles.length]; 709 for (int i = 0; i < embeddedProfiles.length; i++) { 710 embeddedIccids[i] = embeddedProfiles[i].getIccid(); 711 } 712 713 // Note that this only tracks whether we make any writes to the DB. It's possible this will 714 // be set to true for an update even when the row contents remain exactly unchanged from 715 // before, since we don't compare against the previous value. Since this is only intended to 716 // avoid some spurious broadcasts (particularly for users who don't use eSIM at all), this 717 // is fine. 718 boolean hasChanges = false; 719 720 // Update or insert records for all embedded subscriptions (except non-removable ones if the 721 // current eUICC is non-removable, since we assume these are still accessible though not 722 // returned by the eUICC controller). 723 List<SubscriptionInfo> existingSubscriptions = SubscriptionController.getInstance() 724 .getSubscriptionInfoListForEmbeddedSubscriptionUpdate(embeddedIccids, isRemovable); 725 ContentResolver contentResolver = mContext.getContentResolver(); 726 for (EuiccProfileInfo embeddedProfile : embeddedProfiles) { 727 int index = 728 findSubscriptionInfoForIccid(existingSubscriptions, embeddedProfile.getIccid()); 729 if (index < 0) { 730 // No existing entry for this ICCID; create an empty one. 731 SubscriptionController.getInstance().insertEmptySubInfoRecord( 732 embeddedProfile.getIccid(), SubscriptionManager.SIM_NOT_INSERTED); 733 } else { 734 existingSubscriptions.remove(index); 735 } 736 ContentValues values = new ContentValues(); 737 values.put(SubscriptionManager.IS_EMBEDDED, 1); 738 List<UiccAccessRule> ruleList = embeddedProfile.getUiccAccessRules(); 739 boolean isRuleListEmpty = false; 740 if (ruleList == null || ruleList.size() == 0) { 741 isRuleListEmpty = true; 742 } 743 values.put(SubscriptionManager.ACCESS_RULES, 744 isRuleListEmpty ? null : UiccAccessRule.encodeRules( 745 ruleList.toArray(new UiccAccessRule[ruleList.size()]))); 746 values.put(SubscriptionManager.IS_REMOVABLE, isRemovable); 747 values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.getNickname()); 748 values.put(SubscriptionManager.NAME_SOURCE, SubscriptionManager.NAME_SOURCE_USER_INPUT); 749 hasChanges = true; 750 contentResolver.update(SubscriptionManager.CONTENT_URI, values, 751 SubscriptionManager.ICC_ID + "=\"" + embeddedProfile.getIccid() + "\"", null); 752 753 // refresh Cached Active Subscription Info List 754 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList(); 755 } 756 757 // Remove all remaining subscriptions which have embedded = true. We set embedded to false 758 // to ensure they are not returned in the list of embedded subscriptions (but keep them 759 // around in case the subscription is added back later, which is equivalent to a removable 760 // SIM being removed and reinserted). 761 if (!existingSubscriptions.isEmpty()) { 762 List<String> iccidsToRemove = new ArrayList<>(); 763 for (int i = 0; i < existingSubscriptions.size(); i++) { 764 SubscriptionInfo info = existingSubscriptions.get(i); 765 if (info.isEmbedded()) { 766 iccidsToRemove.add("\"" + info.getIccId() + "\""); 767 } 768 } 769 String whereClause = SubscriptionManager.ICC_ID + " IN (" 770 + TextUtils.join(",", iccidsToRemove) + ")"; 771 ContentValues values = new ContentValues(); 772 values.put(SubscriptionManager.IS_EMBEDDED, 0); 773 hasChanges = true; 774 contentResolver.update(SubscriptionManager.CONTENT_URI, values, whereClause, null); 775 776 // refresh Cached Active Subscription Info List 777 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList(); 778 } 779 780 return hasChanges; 781 } 782 findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid)783 private static int findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid) { 784 for (int i = 0; i < list.size(); i++) { 785 if (TextUtils.equals(iccid, list.get(i).getIccId())) { 786 return i; 787 } 788 } 789 return -1; 790 } 791 isNewSim(String iccId, String decIccId, String[] oldIccId)792 private boolean isNewSim(String iccId, String decIccId, String[] oldIccId) { 793 boolean newSim = true; 794 for(int i = 0; i < PROJECT_SIM_NUM; i++) { 795 if(iccId.equals(oldIccId[i])) { 796 newSim = false; 797 break; 798 } else if (decIccId != null && decIccId.equals(oldIccId[i])) { 799 newSim = false; 800 break; 801 } 802 } 803 logd("newSim = " + newSim); 804 805 return newSim; 806 } 807 broadcastSimStateChanged(int slotId, String state, String reason)808 private void broadcastSimStateChanged(int slotId, String state, String reason) { 809 Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 810 // TODO - we'd like this intent to have a single snapshot of all sim state, 811 // but until then this should not use REPLACE_PENDING or we may lose 812 // information 813 // i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 814 // | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 815 i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 816 i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); 817 i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state); 818 i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); 819 SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId); 820 logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + reason + 821 " for mCardIndex: " + slotId); 822 IntentBroadcaster.getInstance().broadcastStickyIntent(i, slotId); 823 } 824 broadcastSimCardStateChanged(int phoneId, int state)825 private void broadcastSimCardStateChanged(int phoneId, int state) { 826 if (state != sSimCardState[phoneId]) { 827 sSimCardState[phoneId] = state; 828 Intent i = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); 829 i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 830 i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 831 i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); 832 SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId); 833 logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + simStateString(state) 834 + " for phone: " + phoneId); 835 mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 836 } 837 } 838 broadcastSimApplicationStateChanged(int phoneId, int state)839 private void broadcastSimApplicationStateChanged(int phoneId, int state) { 840 // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY, 841 // because that's the initial state and a broadcast should be sent only on a transition 842 // after SIM is PRESENT 843 if (!(state == sSimApplicationState[phoneId] 844 || (state == TelephonyManager.SIM_STATE_NOT_READY 845 && sSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN))) { 846 sSimApplicationState[phoneId] = state; 847 Intent i = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); 848 i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 849 i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 850 i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); 851 SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId); 852 logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + simStateString(state) 853 + " for phone: " + phoneId); 854 mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 855 } 856 } 857 simStateString(int state)858 private static String simStateString(int state) { 859 switch (state) { 860 case TelephonyManager.SIM_STATE_UNKNOWN: 861 return "UNKNOWN"; 862 case TelephonyManager.SIM_STATE_ABSENT: 863 return "ABSENT"; 864 case TelephonyManager.SIM_STATE_PIN_REQUIRED: 865 return "PIN_REQUIRED"; 866 case TelephonyManager.SIM_STATE_PUK_REQUIRED: 867 return "PUK_REQUIRED"; 868 case TelephonyManager.SIM_STATE_NETWORK_LOCKED: 869 return "NETWORK_LOCKED"; 870 case TelephonyManager.SIM_STATE_READY: 871 return "READY"; 872 case TelephonyManager.SIM_STATE_NOT_READY: 873 return "NOT_READY"; 874 case TelephonyManager.SIM_STATE_PERM_DISABLED: 875 return "PERM_DISABLED"; 876 case TelephonyManager.SIM_STATE_CARD_IO_ERROR: 877 return "CARD_IO_ERROR"; 878 case TelephonyManager.SIM_STATE_CARD_RESTRICTED: 879 return "CARD_RESTRICTED"; 880 case TelephonyManager.SIM_STATE_LOADED: 881 return "LOADED"; 882 case TelephonyManager.SIM_STATE_PRESENT: 883 return "PRESENT"; 884 default: 885 return "INVALID"; 886 } 887 } 888 logd(String message)889 private void logd(String message) { 890 Rlog.d(LOG_TAG, message); 891 } 892 dump(FileDescriptor fd, PrintWriter pw, String[] args)893 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 894 pw.println("SubscriptionInfoUpdater:"); 895 mCarrierServiceBindHelper.dump(fd, pw, args); 896 } 897 } 898