Home | History | Annotate | Download | only in telephony
      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 
    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 
    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 
    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 
    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 
    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
    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 
    294     void requestEmbeddedSubscriptionInfoListRefresh(@Nullable Runnable callback) {
    295         sendMessage(obtainMessage(EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, callback));
    296     }
    297 
    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 
    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 
    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 
    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 
    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 
    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      */
    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)
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    889     private void logd(String message) {
    890         Rlog.d(LOG_TAG, message);
    891     }
    892 
    893     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
    894         pw.println("SubscriptionInfoUpdater:");
    895         mCarrierServiceBindHelper.dump(fd, pw, args);
    896     }
    897 }
    898