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.annotation.UnsupportedAppUsage; 22 import android.app.ActivityManager; 23 import android.app.UserSwitchObserver; 24 import android.content.ContentResolver; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.Intent; 28 import android.content.SharedPreferences; 29 import android.content.pm.IPackageManager; 30 import android.os.AsyncResult; 31 import android.os.Handler; 32 import android.os.IRemoteCallback; 33 import android.os.Looper; 34 import android.os.Message; 35 import android.os.ParcelUuid; 36 import android.os.PersistableBundle; 37 import android.os.RemoteException; 38 import android.os.ServiceManager; 39 import android.preference.PreferenceManager; 40 import android.provider.Settings; 41 import android.provider.Settings.Global; 42 import android.provider.Settings.SettingNotFoundException; 43 import android.service.carrier.CarrierIdentifier; 44 import android.service.carrier.CarrierService; 45 import android.service.euicc.EuiccProfileInfo; 46 import android.service.euicc.EuiccService; 47 import android.service.euicc.GetEuiccProfileInfoListResult; 48 import android.telephony.CarrierConfigManager; 49 import android.telephony.Rlog; 50 import android.telephony.SubscriptionInfo; 51 import android.telephony.SubscriptionManager; 52 import android.telephony.TelephonyManager; 53 import android.telephony.UiccAccessRule; 54 import android.telephony.euicc.EuiccManager; 55 import android.text.TextUtils; 56 57 import com.android.internal.annotations.VisibleForTesting; 58 import com.android.internal.telephony.euicc.EuiccController; 59 import com.android.internal.telephony.metrics.TelephonyMetrics; 60 import com.android.internal.telephony.uicc.IccRecords; 61 import com.android.internal.telephony.uicc.IccUtils; 62 import com.android.internal.telephony.uicc.UiccCard; 63 import com.android.internal.telephony.uicc.UiccController; 64 import com.android.internal.telephony.uicc.UiccSlot; 65 66 import java.io.FileDescriptor; 67 import java.io.PrintWriter; 68 import java.util.ArrayList; 69 import java.util.List; 70 71 /** 72 *@hide 73 */ 74 public class SubscriptionInfoUpdater extends Handler { 75 private static final String LOG_TAG = "SubscriptionInfoUpdater"; 76 @UnsupportedAppUsage 77 private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount(); 78 79 private static final boolean DBG = true; 80 81 private static final int EVENT_INVALID = -1; 82 private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2; 83 private static final int EVENT_SIM_LOADED = 3; 84 private static final int EVENT_SIM_ABSENT = 4; 85 private static final int EVENT_SIM_LOCKED = 5; 86 private static final int EVENT_SIM_IO_ERROR = 6; 87 private static final int EVENT_SIM_UNKNOWN = 7; 88 private static final int EVENT_SIM_RESTRICTED = 8; 89 private static final int EVENT_SIM_NOT_READY = 9; 90 private static final int EVENT_SIM_READY = 10; 91 private static final int EVENT_SIM_IMSI = 11; 92 private static final int EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS = 12; 93 94 private static final String ICCID_STRING_FOR_NO_SIM = ""; 95 96 private static final ParcelUuid REMOVE_GROUP_UUID = 97 ParcelUuid.fromString(CarrierConfigManager.REMOVE_GROUP_UUID_STRING); 98 99 // Key used to read/write the current IMSI. Updated on SIM_STATE_CHANGED - LOADED. 100 public static final String CURR_SUBID = "curr_subid"; 101 102 @UnsupportedAppUsage 103 private static Phone[] mPhone; 104 @UnsupportedAppUsage 105 private static Context mContext = null; 106 @UnsupportedAppUsage 107 private static String mIccId[] = new String[PROJECT_SIM_NUM]; 108 private static int[] sSimCardState = new int[PROJECT_SIM_NUM]; 109 private static int[] sSimApplicationState = new int[PROJECT_SIM_NUM]; 110 private static boolean sIsSubInfoInitialized = false; 111 private SubscriptionManager mSubscriptionManager = null; 112 private EuiccManager mEuiccManager; 113 @UnsupportedAppUsage 114 private IPackageManager mPackageManager; 115 private Handler mBackgroundHandler; 116 117 // The current foreground user ID. 118 @UnsupportedAppUsage 119 private int mCurrentlyActiveUserId; 120 private CarrierServiceBindHelper mCarrierServiceBindHelper; 121 122 /** 123 * Runnable with a boolean parameter. This is used in 124 * updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback). 125 */ 126 private interface UpdateEmbeddedSubsCallback { 127 /** 128 * Callback of the Runnable. 129 * @param hasChanges Whether there is any subscription info change. If yes, we need to 130 * notify the listeners. 131 */ run(boolean hasChanges)132 void run(boolean hasChanges); 133 } 134 135 // TODO: The SubscriptionController instance should be passed in here from PhoneFactory 136 // rather than invoking the static getter all over the place. SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci)137 public SubscriptionInfoUpdater( 138 Looper looper, Context context, Phone[] phone, CommandsInterface[] ci) { 139 this(looper, context, phone, ci, 140 IPackageManager.Stub.asInterface(ServiceManager.getService("package"))); 141 } 142 SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci, IPackageManager packageMgr)143 @VisibleForTesting public SubscriptionInfoUpdater( 144 Looper looper, Context context, Phone[] phone, 145 CommandsInterface[] ci, IPackageManager packageMgr) { 146 logd("Constructor invoked"); 147 mBackgroundHandler = new Handler(looper); 148 149 mContext = context; 150 mPhone = phone; 151 mSubscriptionManager = SubscriptionManager.from(mContext); 152 mEuiccManager = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE); 153 mPackageManager = packageMgr; 154 155 mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext); 156 initializeCarrierApps(); 157 } 158 initializeCarrierApps()159 private void initializeCarrierApps() { 160 // Initialize carrier apps: 161 // -Now (on system startup) 162 // -Whenever new carrier privilege rules might change (new SIM is loaded) 163 // -Whenever we switch to a new user 164 mCurrentlyActiveUserId = 0; 165 try { 166 ActivityManager.getService().registerUserSwitchObserver(new UserSwitchObserver() { 167 @Override 168 public void onUserSwitching(int newUserId, IRemoteCallback reply) 169 throws RemoteException { 170 mCurrentlyActiveUserId = newUserId; 171 CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), 172 mPackageManager, TelephonyManager.getDefault(), 173 mContext.getContentResolver(), mCurrentlyActiveUserId); 174 175 if (reply != null) { 176 try { 177 reply.sendResult(null); 178 } catch (RemoteException e) { 179 } 180 } 181 } 182 }, LOG_TAG); 183 mCurrentlyActiveUserId = ActivityManager.getService().getCurrentUser().id; 184 } catch (RemoteException e) { 185 logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage()); 186 } 187 CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), 188 mPackageManager, TelephonyManager.getDefault(), mContext.getContentResolver(), 189 mCurrentlyActiveUserId); 190 } 191 192 /** 193 * Update subscriptions when given a new ICC state. 194 */ updateInternalIccState(String simStatus, String reason, int slotId, boolean absentAndInactive)195 public void updateInternalIccState(String simStatus, String reason, int slotId, 196 boolean absentAndInactive) { 197 logd("updateInternalIccState to simStatus " + simStatus + " reason " + reason 198 + " slotId " + slotId); 199 int message = internalIccStateToMessage(simStatus); 200 if (message != EVENT_INVALID) { 201 sendMessage(obtainMessage(message, slotId, absentAndInactive ? 1 : 0, reason)); 202 } 203 } 204 internalIccStateToMessage(String simStatus)205 private int internalIccStateToMessage(String simStatus) { 206 switch(simStatus) { 207 case IccCardConstants.INTENT_VALUE_ICC_ABSENT: return EVENT_SIM_ABSENT; 208 case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: return EVENT_SIM_UNKNOWN; 209 case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: return EVENT_SIM_IO_ERROR; 210 case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: return EVENT_SIM_RESTRICTED; 211 case IccCardConstants.INTENT_VALUE_ICC_NOT_READY: return EVENT_SIM_NOT_READY; 212 case IccCardConstants.INTENT_VALUE_ICC_LOCKED: return EVENT_SIM_LOCKED; 213 case IccCardConstants.INTENT_VALUE_ICC_LOADED: return EVENT_SIM_LOADED; 214 case IccCardConstants.INTENT_VALUE_ICC_READY: return EVENT_SIM_READY; 215 case IccCardConstants.INTENT_VALUE_ICC_IMSI: return EVENT_SIM_IMSI; 216 default: 217 logd("Ignoring simStatus: " + simStatus); 218 return EVENT_INVALID; 219 } 220 } 221 222 @UnsupportedAppUsage isAllIccIdQueryDone()223 private boolean isAllIccIdQueryDone() { 224 for (int i = 0; i < PROJECT_SIM_NUM; i++) { 225 UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(i); 226 int slotId = UiccController.getInstance().getSlotIdFromPhoneId(i); 227 if (mIccId[i] == null || slot == null || !slot.isActive()) { 228 if (mIccId[i] == null) { 229 logd("Wait for SIM " + i + " Iccid"); 230 } else { 231 logd(String.format("Wait for slot corresponding to phone %d to be active, " 232 + "slotId is %d", i, slotId)); 233 } 234 return false; 235 } 236 } 237 logd("All IccIds query complete"); 238 239 return true; 240 } 241 242 @Override handleMessage(Message msg)243 public void handleMessage(Message msg) { 244 List<Integer> cardIds = new ArrayList<>(); 245 switch (msg.what) { 246 case EVENT_GET_NETWORK_SELECTION_MODE_DONE: { 247 AsyncResult ar = (AsyncResult)msg.obj; 248 Integer slotId = (Integer)ar.userObj; 249 if (ar.exception == null && ar.result != null) { 250 int[] modes = (int[])ar.result; 251 if (modes[0] == 1) { // Manual mode. 252 mPhone[slotId].setNetworkSelectionModeAutomatic(null); 253 } 254 } else { 255 logd("EVENT_GET_NETWORK_SELECTION_MODE_DONE: error getting network mode."); 256 } 257 break; 258 } 259 260 case EVENT_SIM_LOADED: 261 handleSimLoaded(msg.arg1); 262 break; 263 264 case EVENT_SIM_ABSENT: 265 handleSimAbsent(msg.arg1, msg.arg2); 266 break; 267 268 case EVENT_SIM_LOCKED: 269 handleSimLocked(msg.arg1, (String) msg.obj); 270 break; 271 272 case EVENT_SIM_UNKNOWN: 273 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null); 274 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN); 275 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN); 276 updateSubscriptionCarrierId(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN); 277 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN); 278 break; 279 280 case EVENT_SIM_IO_ERROR: 281 handleSimError(msg.arg1); 282 break; 283 284 case EVENT_SIM_RESTRICTED: 285 broadcastSimStateChanged(msg.arg1, 286 IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED, 287 IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); 288 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_CARD_RESTRICTED); 289 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); 290 updateSubscriptionCarrierId(msg.arg1, 291 IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); 292 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED); 293 break; 294 295 case EVENT_SIM_READY: 296 cardIds.add(getCardIdFromPhoneId(msg.arg1)); 297 updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { 298 if (hasChanges) { 299 SubscriptionController.getInstance().notifySubscriptionInfoChanged(); 300 } 301 }); 302 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null); 303 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT); 304 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY); 305 break; 306 307 case EVENT_SIM_IMSI: 308 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_IMSI, null); 309 break; 310 311 case EVENT_SIM_NOT_READY: 312 // an eUICC with no active subscriptions never becomes ready, so we need to trigger 313 // the embedded subscriptions update here 314 cardIds.add(getCardIdFromPhoneId(msg.arg1)); 315 updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { 316 if (hasChanges) { 317 SubscriptionController.getInstance().notifySubscriptionInfoChanged(); 318 } 319 }); 320 handleSimNotReady(msg.arg1); 321 break; 322 323 case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS: 324 cardIds.add(msg.arg1); 325 Runnable r = (Runnable) msg.obj; 326 updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { 327 if (hasChanges) { 328 SubscriptionController.getInstance().notifySubscriptionInfoChanged(); 329 } 330 if (r != null) { 331 r.run(); 332 } 333 }); 334 break; 335 336 default: 337 logd("Unknown msg:" + msg.what); 338 } 339 } 340 getCardIdFromPhoneId(int phoneId)341 private int getCardIdFromPhoneId(int phoneId) { 342 UiccController uiccController = UiccController.getInstance(); 343 UiccCard card = uiccController.getUiccCardForPhone(phoneId); 344 if (card != null) { 345 return uiccController.convertToPublicCardId(card.getCardId()); 346 } 347 return TelephonyManager.UNINITIALIZED_CARD_ID; 348 } 349 requestEmbeddedSubscriptionInfoListRefresh(int cardId, @Nullable Runnable callback)350 void requestEmbeddedSubscriptionInfoListRefresh(int cardId, @Nullable Runnable callback) { 351 sendMessage(obtainMessage( 352 EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback)); 353 } 354 handleSimLocked(int slotId, String reason)355 private void handleSimLocked(int slotId, String reason) { 356 if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) { 357 logd("SIM" + (slotId + 1) + " hot plug in"); 358 mIccId[slotId] = null; 359 } 360 361 String iccId = mIccId[slotId]; 362 if (iccId == null) { 363 IccCard iccCard = mPhone[slotId].getIccCard(); 364 if (iccCard == null) { 365 logd("handleSimLocked: IccCard null"); 366 return; 367 } 368 IccRecords records = iccCard.getIccRecords(); 369 if (records == null) { 370 logd("handleSimLocked: IccRecords null"); 371 return; 372 } 373 if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) { 374 logd("handleSimLocked: IccID null"); 375 return; 376 } 377 mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId()); 378 } else { 379 logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId); 380 } 381 382 updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); 383 384 broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason); 385 broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT); 386 broadcastSimApplicationStateChanged(slotId, getSimStateFromLockedReason(reason)); 387 updateSubscriptionCarrierId(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED); 388 updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED); 389 } 390 getSimStateFromLockedReason(String lockedReason)391 private static int getSimStateFromLockedReason(String lockedReason) { 392 switch (lockedReason) { 393 case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN: 394 return TelephonyManager.SIM_STATE_PIN_REQUIRED; 395 case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK: 396 return TelephonyManager.SIM_STATE_PUK_REQUIRED; 397 case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK: 398 return TelephonyManager.SIM_STATE_NETWORK_LOCKED; 399 case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED: 400 return TelephonyManager.SIM_STATE_PERM_DISABLED; 401 default: 402 Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason); 403 return TelephonyManager.SIM_STATE_UNKNOWN; 404 } 405 } 406 handleSimNotReady(int slotId)407 private void handleSimNotReady(int slotId) { 408 logd("handleSimNotReady: slotId: " + slotId); 409 410 IccCard iccCard = mPhone[slotId].getIccCard(); 411 if (iccCard.isEmptyProfile()) { 412 // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this 413 // phase, the subscription list is accessible. Treating NOT_READY 414 // as equivalent to ABSENT, once the rest of the system can handle it. 415 mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; 416 updateSubscriptionInfoByIccId(slotId, false /* updateEmbeddedSubs */); 417 } 418 419 broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY, 420 null); 421 broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT); 422 broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY); 423 } 424 handleSimLoaded(int slotId)425 private void handleSimLoaded(int slotId) { 426 logd("handleSimLoaded: slotId: " + slotId); 427 428 // The SIM should be loaded at this state, but it is possible in cases such as SIM being 429 // removed or a refresh RESET that the IccRecords could be null. The right behavior is to 430 // not broadcast the SIM loaded. 431 int loadedSlotId = slotId; 432 IccCard iccCard = mPhone[slotId].getIccCard(); 433 if (iccCard == null) { // Possibly a race condition. 434 logd("handleSimLoaded: IccCard null"); 435 return; 436 } 437 IccRecords records = iccCard.getIccRecords(); 438 if (records == null) { // Possibly a race condition. 439 logd("handleSimLoaded: IccRecords null"); 440 return; 441 } 442 if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) { 443 logd("handleSimLoaded: IccID null"); 444 return; 445 } 446 mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId()); 447 448 updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); 449 List<SubscriptionInfo> subscriptionInfos = SubscriptionController.getInstance() 450 .getSubInfoUsingSlotIndexPrivileged(slotId); 451 if (subscriptionInfos == null || subscriptionInfos.isEmpty()) { 452 loge("empty subinfo for slotId: " + slotId + "could not update ContentResolver"); 453 } else { 454 for (SubscriptionInfo sub : subscriptionInfos) { 455 int subId = sub.getSubscriptionId(); 456 TelephonyManager tm = (TelephonyManager) 457 mContext.getSystemService(Context.TELEPHONY_SERVICE); 458 String operator = tm.getSimOperatorNumeric(subId); 459 460 if (!TextUtils.isEmpty(operator)) { 461 if (subId == SubscriptionController.getInstance().getDefaultSubId()) { 462 MccTable.updateMccMncConfiguration(mContext, operator); 463 } 464 SubscriptionController.getInstance().setMccMnc(operator, subId); 465 } else { 466 logd("EVENT_RECORDS_LOADED Operator name is null"); 467 } 468 469 String iso = tm.getSimCountryIsoForPhone(slotId); 470 471 if (!TextUtils.isEmpty(iso)) { 472 SubscriptionController.getInstance().setCountryIso(iso, subId); 473 } else { 474 logd("EVENT_RECORDS_LOADED sim country iso is null"); 475 } 476 477 String msisdn = tm.getLine1Number(subId); 478 if (msisdn != null) { 479 SubscriptionController.getInstance().setDisplayNumber(msisdn, subId); 480 } 481 482 String imsi = tm.createForSubscriptionId(subId).getSubscriberId(); 483 if (imsi != null) { 484 SubscriptionController.getInstance().setImsi(imsi, subId); 485 } 486 487 String[] ehplmns = records.getEhplmns(); 488 String[] hplmns = records.getPlmnsFromHplmnActRecord(); 489 if (ehplmns != null || hplmns != null) { 490 SubscriptionController.getInstance().setAssociatedPlmns(ehplmns, hplmns, subId); 491 } 492 493 /* Update preferred network type and network selection mode on SIM change. 494 * Storing last subId in SharedPreference for now to detect SIM change. 495 */ 496 SharedPreferences sp = 497 PreferenceManager.getDefaultSharedPreferences(mContext); 498 int storedSubId = sp.getInt(CURR_SUBID + slotId, -1); 499 500 if (storedSubId != subId) { 501 int networkType = Settings.Global.getInt( 502 mPhone[slotId].getContext().getContentResolver(), 503 Settings.Global.PREFERRED_NETWORK_MODE + subId, 504 -1 /* invalid network mode */); 505 506 if (networkType == -1) { 507 networkType = RILConstants.PREFERRED_NETWORK_MODE; 508 try { 509 networkType = TelephonyManager.getIntAtIndex( 510 mContext.getContentResolver(), 511 Settings.Global.PREFERRED_NETWORK_MODE, slotId); 512 } catch (SettingNotFoundException retrySnfe) { 513 Rlog.e(LOG_TAG, "Settings Exception Reading Value At Index for " 514 + "Settings.Global.PREFERRED_NETWORK_MODE"); 515 } 516 Settings.Global.putInt( 517 mPhone[slotId].getContext().getContentResolver(), 518 Global.PREFERRED_NETWORK_MODE + subId, 519 networkType); 520 } 521 522 // Set the modem network mode 523 mPhone[slotId].setPreferredNetworkType(networkType, null); 524 525 // Only support automatic selection mode on SIM change. 526 mPhone[slotId].getNetworkSelectionMode( 527 obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE, 528 new Integer(slotId))); 529 530 // Update stored subId 531 SharedPreferences.Editor editor = sp.edit(); 532 editor.putInt(CURR_SUBID + slotId, subId); 533 editor.apply(); 534 } 535 } 536 } 537 538 // Update set of enabled carrier apps now that the privilege rules may have changed. 539 CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(), 540 mPackageManager, TelephonyManager.getDefault(), 541 mContext.getContentResolver(), mCurrentlyActiveUserId); 542 543 /** 544 * The sim loading sequence will be 545 * 1. ACTION_SUBINFO_CONTENT_CHANGE happens through updateSubscriptionInfoByIccId() above. 546 * 2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED 547 * /ACTION_SIM_APPLICATION_STATE_CHANGED 548 * 3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED 549 * 4. ACTION_CARRIER_CONFIG_CHANGED 550 */ 551 broadcastSimStateChanged(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null); 552 broadcastSimCardStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_PRESENT); 553 broadcastSimApplicationStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_LOADED); 554 updateSubscriptionCarrierId(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED); 555 updateCarrierServices(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED); 556 } 557 updateCarrierServices(int slotId, String simState)558 private void updateCarrierServices(int slotId, String simState) { 559 CarrierConfigManager configManager = 560 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 561 configManager.updateConfigForPhoneId(slotId, simState); 562 mCarrierServiceBindHelper.updateForPhoneId(slotId, simState); 563 } 564 updateSubscriptionCarrierId(int slotId, String simState)565 private void updateSubscriptionCarrierId(int slotId, String simState) { 566 if (mPhone != null && mPhone[slotId] != null) { 567 mPhone[slotId].resolveSubscriptionCarrierId(simState); 568 } 569 } 570 handleSimAbsent(int slotId, int absentAndInactive)571 private void handleSimAbsent(int slotId, int absentAndInactive) { 572 if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) { 573 logd("SIM" + (slotId + 1) + " hot plug out, absentAndInactive=" + absentAndInactive); 574 } 575 mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; 576 updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); 577 // Do not broadcast if the SIM is absent and inactive, because the logical slotId here is 578 // no longer correct 579 if (absentAndInactive == 0) { 580 broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT, null); 581 broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_ABSENT); 582 broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_UNKNOWN); 583 updateSubscriptionCarrierId(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT); 584 updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT); 585 } 586 } 587 handleSimError(int slotId)588 private void handleSimError(int slotId) { 589 if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) { 590 logd("SIM" + (slotId + 1) + " Error "); 591 } 592 mIccId[slotId] = ICCID_STRING_FOR_NO_SIM; 593 updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */); 594 broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR, 595 IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); 596 broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR); 597 broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY); 598 updateSubscriptionCarrierId(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); 599 updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR); 600 } 601 updateSubscriptionInfoByIccId(int slotIndex, boolean updateEmbeddedSubs)602 private synchronized void updateSubscriptionInfoByIccId(int slotIndex, 603 boolean updateEmbeddedSubs) { 604 logd("updateSubscriptionInfoByIccId:+ Start"); 605 if (!SubscriptionManager.isValidSlotIndex(slotIndex)) { 606 loge("[updateSubscriptionInfoByIccId]- invalid slotIndex=" + slotIndex); 607 return; 608 } 609 logd("updateSubscriptionInfoByIccId: removing subscription info record: slotIndex " 610 + slotIndex); 611 // Clear slotIndex only when sim absent is not enough. It's possible to switch SIM profile 612 // within the same slot. Need to clear the slot index of the previous sub. Thus always clear 613 // for the changing slot first. 614 SubscriptionController.getInstance().clearSubInfoRecord(slotIndex); 615 616 // If SIM is not absent, insert new record or update existing record. 617 if (!ICCID_STRING_FOR_NO_SIM.equals(mIccId[slotIndex])) { 618 logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: " 619 + mIccId[slotIndex] + "slot: " + slotIndex); 620 mSubscriptionManager.addSubscriptionInfoRecord(mIccId[slotIndex], slotIndex); 621 } 622 623 List<SubscriptionInfo> subInfos = SubscriptionController.getInstance() 624 .getSubInfoUsingSlotIndexPrivileged(slotIndex); 625 if (subInfos != null) { 626 boolean changed = false; 627 for (int i = 0; i < subInfos.size(); i++) { 628 SubscriptionInfo temp = subInfos.get(i); 629 ContentValues value = new ContentValues(1); 630 631 String msisdn = TelephonyManager.getDefault().getLine1Number( 632 temp.getSubscriptionId()); 633 634 if (!TextUtils.equals(msisdn, temp.getNumber())) { 635 value.put(SubscriptionManager.NUMBER, msisdn); 636 mContext.getContentResolver().update(SubscriptionManager.getUriForSubscriptionId( 637 temp.getSubscriptionId()), value, null, null); 638 changed = true; 639 } 640 } 641 if (changed) { 642 // refresh Cached Active Subscription Info List 643 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList(); 644 } 645 } 646 647 // TODO investigate if we can update for each slot separately. 648 if (isAllIccIdQueryDone()) { 649 // Ensure the modems are mapped correctly 650 if (mSubscriptionManager.isActiveSubId( 651 mSubscriptionManager.getDefaultDataSubscriptionId())) { 652 mSubscriptionManager.setDefaultDataSubId( 653 mSubscriptionManager.getDefaultDataSubscriptionId()); 654 } else { 655 logd("bypass reset default data sub if inactive"); 656 } 657 setSubInfoInitialized(); 658 } 659 660 UiccController uiccController = UiccController.getInstance(); 661 UiccSlot[] uiccSlots = uiccController.getUiccSlots(); 662 if (uiccSlots != null && updateEmbeddedSubs) { 663 List<Integer> cardIds = new ArrayList<>(); 664 for (UiccSlot uiccSlot : uiccSlots) { 665 if (uiccSlot != null && uiccSlot.getUiccCard() != null) { 666 int cardId = uiccController.convertToPublicCardId( 667 uiccSlot.getUiccCard().getCardId()); 668 cardIds.add(cardId); 669 } 670 } 671 updateEmbeddedSubscriptions(cardIds, (hasChanges) -> { 672 if (hasChanges) { 673 SubscriptionController.getInstance().notifySubscriptionInfoChanged(); 674 } 675 if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); 676 }); 677 } 678 679 SubscriptionController.getInstance().notifySubscriptionInfoChanged(); 680 if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete"); 681 } 682 setSubInfoInitialized()683 private static void setSubInfoInitialized() { 684 // Should only be triggered once. 685 if (!sIsSubInfoInitialized) { 686 if (DBG) logd("SubInfo Initialized"); 687 sIsSubInfoInitialized = true; 688 SubscriptionController.getInstance().notifySubInfoReady(); 689 MultiSimSettingController.getInstance().notifyAllSubscriptionLoaded(); 690 } 691 } 692 693 /** 694 * Whether subscriptions of all SIMs are initialized. 695 */ isSubInfoInitialized()696 public static boolean isSubInfoInitialized() { 697 return sIsSubInfoInitialized; 698 } 699 700 /** 701 * Updates the cached list of embedded subscription for the eUICC with the given list of card 702 * IDs {@code cardIds}. The step of reading the embedded subscription list from eUICC card is 703 * executed in background thread. The callback {@code callback} is executed after the cache is 704 * refreshed. The callback is executed in main thread. 705 */ 706 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback callback)707 public void updateEmbeddedSubscriptions(List<Integer> cardIds, 708 @Nullable UpdateEmbeddedSubsCallback callback) { 709 // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they 710 // are filtered out of list calls as long as EuiccManager.isEnabled returns false). 711 if (!mEuiccManager.isEnabled()) { 712 callback.run(false /* hasChanges */); 713 return; 714 } 715 716 mBackgroundHandler.post(() -> { 717 List<GetEuiccProfileInfoListResult> results = new ArrayList<>(); 718 for (int cardId : cardIds) { 719 GetEuiccProfileInfoListResult result = 720 EuiccController.get().blockingGetEuiccProfileInfoList(cardId); 721 if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId); 722 results.add(result); 723 } 724 725 // The runnable will be executed in the main thread. 726 this.post(() -> { 727 boolean hasChanges = false; 728 for (GetEuiccProfileInfoListResult result : results) { 729 if (updateEmbeddedSubscriptionsCache(result)) { 730 hasChanges = true; 731 } 732 } 733 // The latest state in the main thread may be changed when the callback is 734 // triggered. 735 if (callback != null) { 736 callback.run(hasChanges); 737 } 738 }); 739 }); 740 } 741 742 /** 743 * Update the cached list of embedded subscription based on the passed in 744 * GetEuiccProfileInfoListResult {@code result}. 745 * 746 * @return true if changes may have been made. This is not a guarantee that changes were made, 747 * but notifications about subscription changes may be skipped if this returns false as an 748 * optimization to avoid spurious notifications. 749 */ updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result)750 private boolean updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result) { 751 if (DBG) logd("updateEmbeddedSubscriptionsCache"); 752 753 if (result == null) { 754 // IPC to the eUICC controller failed. 755 return false; 756 } 757 758 // If the returned result is not RESULT_OK or the profile list is null, don't update cache. 759 // Otherwise, update the cache. 760 final EuiccProfileInfo[] embeddedProfiles; 761 List<EuiccProfileInfo> list = result.getProfiles(); 762 if (result.getResult() == EuiccService.RESULT_OK && list != null) { 763 embeddedProfiles = list.toArray(new EuiccProfileInfo[list.size()]); 764 if (DBG) { 765 logd("blockingGetEuiccProfileInfoList: got " + result.getProfiles().size() 766 + " profiles"); 767 } 768 } else { 769 if (DBG) { 770 logd("blockingGetEuiccProfileInfoList returns an error. " 771 + "Result code=" + result.getResult() 772 + ". Null profile list=" + (result.getProfiles() == null)); 773 } 774 return false; 775 } 776 777 final boolean isRemovable = result.getIsRemovable(); 778 779 final String[] embeddedIccids = new String[embeddedProfiles.length]; 780 for (int i = 0; i < embeddedProfiles.length; i++) { 781 embeddedIccids[i] = embeddedProfiles[i].getIccid(); 782 } 783 784 if (DBG) logd("Get eUICC profile list of size " + embeddedProfiles.length); 785 786 // Note that this only tracks whether we make any writes to the DB. It's possible this will 787 // be set to true for an update even when the row contents remain exactly unchanged from 788 // before, since we don't compare against the previous value. Since this is only intended to 789 // avoid some spurious broadcasts (particularly for users who don't use eSIM at all), this 790 // is fine. 791 boolean hasChanges = false; 792 793 // Update or insert records for all embedded subscriptions (except non-removable ones if the 794 // current eUICC is non-removable, since we assume these are still accessible though not 795 // returned by the eUICC controller). 796 List<SubscriptionInfo> existingSubscriptions = SubscriptionController.getInstance() 797 .getSubscriptionInfoListForEmbeddedSubscriptionUpdate(embeddedIccids, isRemovable); 798 ContentResolver contentResolver = mContext.getContentResolver(); 799 for (EuiccProfileInfo embeddedProfile : embeddedProfiles) { 800 int index = 801 findSubscriptionInfoForIccid(existingSubscriptions, embeddedProfile.getIccid()); 802 int prevCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID; 803 int nameSource = SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE; 804 if (index < 0) { 805 // No existing entry for this ICCID; create an empty one. 806 SubscriptionController.getInstance().insertEmptySubInfoRecord( 807 embeddedProfile.getIccid(), SubscriptionManager.SIM_NOT_INSERTED); 808 } else { 809 nameSource = existingSubscriptions.get(index).getNameSource(); 810 prevCarrierId = existingSubscriptions.get(index).getCarrierId(); 811 existingSubscriptions.remove(index); 812 } 813 814 if (DBG) { 815 logd("embeddedProfile " + embeddedProfile + " existing record " 816 + (index < 0 ? "not found" : "found")); 817 } 818 819 ContentValues values = new ContentValues(); 820 values.put(SubscriptionManager.IS_EMBEDDED, 1); 821 List<UiccAccessRule> ruleList = embeddedProfile.getUiccAccessRules(); 822 boolean isRuleListEmpty = false; 823 if (ruleList == null || ruleList.size() == 0) { 824 isRuleListEmpty = true; 825 } 826 values.put(SubscriptionManager.ACCESS_RULES, 827 isRuleListEmpty ? null : UiccAccessRule.encodeRules( 828 ruleList.toArray(new UiccAccessRule[ruleList.size()]))); 829 values.put(SubscriptionManager.IS_REMOVABLE, isRemovable); 830 // override DISPLAY_NAME if the priority of existing nameSource is <= carrier 831 if (SubscriptionController.getNameSourcePriority(nameSource) 832 <= SubscriptionController.getNameSourcePriority( 833 SubscriptionManager.NAME_SOURCE_CARRIER)) { 834 values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.getNickname()); 835 values.put(SubscriptionManager.NAME_SOURCE, 836 SubscriptionManager.NAME_SOURCE_CARRIER); 837 } 838 values.put(SubscriptionManager.PROFILE_CLASS, embeddedProfile.getProfileClass()); 839 CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier(); 840 if (cid != null) { 841 // Due to the limited subscription information, carrier id identified here might 842 // not be accurate compared with CarrierResolver. Only update carrier id if there 843 // is no valid carrier id present. 844 if (prevCarrierId == TelephonyManager.UNKNOWN_CARRIER_ID) { 845 values.put(SubscriptionManager.CARRIER_ID, 846 CarrierResolver.getCarrierIdFromIdentifier(mContext, cid)); 847 } 848 String mcc = cid.getMcc(); 849 String mnc = cid.getMnc(); 850 values.put(SubscriptionManager.MCC_STRING, mcc); 851 values.put(SubscriptionManager.MCC, mcc); 852 values.put(SubscriptionManager.MNC_STRING, mnc); 853 values.put(SubscriptionManager.MNC, mnc); 854 } 855 hasChanges = true; 856 contentResolver.update(SubscriptionManager.CONTENT_URI, values, 857 SubscriptionManager.ICC_ID + "=\"" + embeddedProfile.getIccid() + "\"", null); 858 859 // refresh Cached Active Subscription Info List 860 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList(); 861 } 862 863 // Remove all remaining subscriptions which have embedded = true. We set embedded to false 864 // to ensure they are not returned in the list of embedded subscriptions (but keep them 865 // around in case the subscription is added back later, which is equivalent to a removable 866 // SIM being removed and reinserted). 867 if (!existingSubscriptions.isEmpty()) { 868 if (DBG) { 869 logd("Removing existing embedded subscriptions of size" 870 + existingSubscriptions.size()); 871 } 872 List<String> iccidsToRemove = new ArrayList<>(); 873 for (int i = 0; i < existingSubscriptions.size(); i++) { 874 SubscriptionInfo info = existingSubscriptions.get(i); 875 if (info.isEmbedded()) { 876 if (DBG) logd("Removing embedded subscription of IccId " + info.getIccId()); 877 iccidsToRemove.add("\"" + info.getIccId() + "\""); 878 } 879 } 880 String whereClause = SubscriptionManager.ICC_ID + " IN (" 881 + TextUtils.join(",", iccidsToRemove) + ")"; 882 ContentValues values = new ContentValues(); 883 values.put(SubscriptionManager.IS_EMBEDDED, 0); 884 hasChanges = true; 885 contentResolver.update(SubscriptionManager.CONTENT_URI, values, whereClause, null); 886 887 // refresh Cached Active Subscription Info List 888 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList(); 889 } 890 891 if (DBG) logd("updateEmbeddedSubscriptions done hasChanges=" + hasChanges); 892 return hasChanges; 893 } 894 895 /** 896 * Called by CarrierConfigLoader to update the subscription before sending a broadcast. 897 */ updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId, String configPackageName, PersistableBundle config, Message onComplete)898 public void updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId, 899 String configPackageName, PersistableBundle config, Message onComplete) { 900 post(() -> { 901 updateSubscriptionByCarrierConfig(phoneId, configPackageName, config); 902 onComplete.sendToTarget(); 903 }); 904 } 905 getDefaultCarrierServicePackageName()906 private String getDefaultCarrierServicePackageName() { 907 CarrierConfigManager configManager = 908 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE); 909 return configManager.getDefaultCarrierServicePackageName(); 910 } 911 isCarrierServicePackage(int phoneId, String pkgName)912 private boolean isCarrierServicePackage(int phoneId, String pkgName) { 913 if (pkgName.equals(getDefaultCarrierServicePackageName())) return false; 914 915 List<String> carrierPackageNames = TelephonyManager.from(mContext) 916 .getCarrierPackageNamesForIntentAndPhone( 917 new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId); 918 if (DBG) logd("Carrier Packages For Subscription = " + carrierPackageNames); 919 return carrierPackageNames != null && carrierPackageNames.contains(pkgName); 920 } 921 922 /** 923 * Update the currently active Subscription based on information from CarrierConfig 924 */ 925 @VisibleForTesting updateSubscriptionByCarrierConfig( int phoneId, String configPackageName, PersistableBundle config)926 public void updateSubscriptionByCarrierConfig( 927 int phoneId, String configPackageName, PersistableBundle config) { 928 if (!SubscriptionManager.isValidPhoneId(phoneId) 929 || TextUtils.isEmpty(configPackageName) || config == null) { 930 if (DBG) { 931 logd("In updateSubscriptionByCarrierConfig(): phoneId=" + phoneId 932 + " configPackageName=" + configPackageName + " config=" 933 + ((config == null) ? "null" : config.hashCode())); 934 } 935 return; 936 } 937 938 SubscriptionController sc = SubscriptionController.getInstance(); 939 if (sc == null) { 940 loge("SubscriptionController was null"); 941 return; 942 } 943 944 int currentSubId = sc.getSubIdUsingPhoneId(phoneId); 945 if (!SubscriptionManager.isValidSubscriptionId(currentSubId) 946 || currentSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) { 947 if (DBG) logd("No subscription is active for phone being updated"); 948 return; 949 } 950 951 SubscriptionInfo currentSubInfo = sc.getSubscriptionInfo(currentSubId); 952 if (currentSubInfo == null) { 953 loge("Couldn't retrieve subscription info for current subscription"); 954 return; 955 } 956 957 if (!isCarrierServicePackage(phoneId, configPackageName)) { 958 loge("Cannot manage subId=" + currentSubId + ", carrierPackage=" + configPackageName); 959 return; 960 } 961 962 ContentValues cv = new ContentValues(); 963 boolean isOpportunistic = config.getBoolean( 964 CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false); 965 if (currentSubInfo.isOpportunistic() != isOpportunistic) { 966 if (DBG) logd("Set SubId=" + currentSubId + " isOpportunistic=" + isOpportunistic); 967 cv.put(SubscriptionManager.IS_OPPORTUNISTIC, isOpportunistic ? "1" : "0"); 968 } 969 970 String groupUuidString = 971 config.getString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, ""); 972 ParcelUuid groupUuid = null; 973 if (!TextUtils.isEmpty(groupUuidString)) { 974 try { 975 // Update via a UUID Structure to ensure consistent formatting 976 groupUuid = ParcelUuid.fromString(groupUuidString); 977 if (groupUuid.equals(REMOVE_GROUP_UUID) 978 && currentSubInfo.getGroupUuid() != null) { 979 cv.put(SubscriptionManager.GROUP_UUID, (String) null); 980 if (DBG) logd("Group Removed for" + currentSubId); 981 } else if (SubscriptionController.getInstance().canPackageManageGroup(groupUuid, 982 configPackageName)) { 983 cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString()); 984 cv.put(SubscriptionManager.GROUP_OWNER, configPackageName); 985 if (DBG) logd("Group Added for" + currentSubId); 986 } else { 987 loge("configPackageName " + configPackageName + " doesn't own grouUuid " 988 + groupUuid); 989 } 990 } catch (IllegalArgumentException e) { 991 loge("Invalid Group UUID=" + groupUuidString); 992 } 993 } 994 if (cv.size() > 0 && mContext.getContentResolver().update(SubscriptionManager 995 .getUriForSubscriptionId(currentSubId), cv, null, null) > 0) { 996 sc.refreshCachedActiveSubscriptionInfoList(); 997 sc.notifySubscriptionInfoChanged(); 998 MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid); 999 } 1000 } 1001 findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid)1002 private static int findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid) { 1003 for (int i = 0; i < list.size(); i++) { 1004 if (TextUtils.equals(iccid, list.get(i).getIccId())) { 1005 return i; 1006 } 1007 } 1008 return -1; 1009 } 1010 isNewSim(String iccId, String decIccId, String[] oldIccId)1011 private boolean isNewSim(String iccId, String decIccId, String[] oldIccId) { 1012 boolean newSim = true; 1013 for(int i = 0; i < PROJECT_SIM_NUM; i++) { 1014 if(iccId.equals(oldIccId[i])) { 1015 newSim = false; 1016 break; 1017 } else if (decIccId != null && decIccId.equals(oldIccId[i])) { 1018 newSim = false; 1019 break; 1020 } 1021 } 1022 logd("newSim = " + newSim); 1023 1024 return newSim; 1025 } 1026 1027 @UnsupportedAppUsage broadcastSimStateChanged(int slotId, String state, String reason)1028 private void broadcastSimStateChanged(int slotId, String state, String reason) { 1029 Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED); 1030 // TODO - we'd like this intent to have a single snapshot of all sim state, 1031 // but until then this should not use REPLACE_PENDING or we may lose 1032 // information 1033 // i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING 1034 // | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1035 i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1036 i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); 1037 i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state); 1038 i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason); 1039 SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId); 1040 logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + reason + 1041 " for phone: " + slotId); 1042 IntentBroadcaster.getInstance().broadcastStickyIntent(i, slotId); 1043 } 1044 broadcastSimCardStateChanged(int phoneId, int state)1045 private void broadcastSimCardStateChanged(int phoneId, int state) { 1046 if (state != sSimCardState[phoneId]) { 1047 sSimCardState[phoneId] = state; 1048 Intent i = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED); 1049 i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1050 i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1051 i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); 1052 SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId); 1053 // TODO(b/130664115) we manually populate this intent with the slotId. In the future we 1054 // should do a review of whether to make this public 1055 int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); 1056 i.putExtra(PhoneConstants.SLOT_KEY, slotId); 1057 logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + simStateString(state) 1058 + " for phone: " + phoneId + " slot: " + slotId); 1059 mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 1060 TelephonyMetrics.getInstance().updateSimState(phoneId, state); 1061 } 1062 } 1063 broadcastSimApplicationStateChanged(int phoneId, int state)1064 private void broadcastSimApplicationStateChanged(int phoneId, int state) { 1065 // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY, 1066 // because that's the initial state and a broadcast should be sent only on a transition 1067 // after SIM is PRESENT 1068 if (!(state == sSimApplicationState[phoneId] 1069 || (state == TelephonyManager.SIM_STATE_NOT_READY 1070 && sSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN))) { 1071 sSimApplicationState[phoneId] = state; 1072 Intent i = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED); 1073 i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); 1074 i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 1075 i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state); 1076 SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId); 1077 // TODO(b/130664115) we populate this intent with the actual slotId. In the future we 1078 // should do a review of whether to make this public 1079 int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId); 1080 i.putExtra(PhoneConstants.SLOT_KEY, slotId); 1081 logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + simStateString(state) 1082 + " for phone: " + phoneId + " slot: " + slotId); 1083 mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE); 1084 TelephonyMetrics.getInstance().updateSimState(phoneId, state); 1085 } 1086 } 1087 simStateString(int state)1088 private static String simStateString(int state) { 1089 switch (state) { 1090 case TelephonyManager.SIM_STATE_UNKNOWN: 1091 return "UNKNOWN"; 1092 case TelephonyManager.SIM_STATE_ABSENT: 1093 return "ABSENT"; 1094 case TelephonyManager.SIM_STATE_PIN_REQUIRED: 1095 return "PIN_REQUIRED"; 1096 case TelephonyManager.SIM_STATE_PUK_REQUIRED: 1097 return "PUK_REQUIRED"; 1098 case TelephonyManager.SIM_STATE_NETWORK_LOCKED: 1099 return "NETWORK_LOCKED"; 1100 case TelephonyManager.SIM_STATE_READY: 1101 return "READY"; 1102 case TelephonyManager.SIM_STATE_NOT_READY: 1103 return "NOT_READY"; 1104 case TelephonyManager.SIM_STATE_PERM_DISABLED: 1105 return "PERM_DISABLED"; 1106 case TelephonyManager.SIM_STATE_CARD_IO_ERROR: 1107 return "CARD_IO_ERROR"; 1108 case TelephonyManager.SIM_STATE_CARD_RESTRICTED: 1109 return "CARD_RESTRICTED"; 1110 case TelephonyManager.SIM_STATE_LOADED: 1111 return "LOADED"; 1112 case TelephonyManager.SIM_STATE_PRESENT: 1113 return "PRESENT"; 1114 default: 1115 return "INVALID"; 1116 } 1117 } 1118 1119 @UnsupportedAppUsage logd(String message)1120 private static void logd(String message) { 1121 Rlog.d(LOG_TAG, message); 1122 } 1123 loge(String message)1124 private static void loge(String message) { 1125 Rlog.e(LOG_TAG, message); 1126 } 1127 dump(FileDescriptor fd, PrintWriter pw, String[] args)1128 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 1129 pw.println("SubscriptionInfoUpdater:"); 1130 mCarrierServiceBindHelper.dump(fd, pw, args); 1131 } 1132 } 1133