1 /*
2  * Copyright (C) 2011-2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.uicc;
18 
19 import static android.telephony.TelephonyManager.UNINITIALIZED_CARD_ID;
20 import static android.telephony.TelephonyManager.UNSUPPORTED_CARD_ID;
21 
22 import static java.util.Arrays.copyOf;
23 
24 import android.app.BroadcastOptions;
25 import android.compat.annotation.UnsupportedAppUsage;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.SharedPreferences;
29 import android.content.pm.PackageManager;
30 import android.os.AsyncResult;
31 import android.os.Handler;
32 import android.os.Message;
33 import android.os.Registrant;
34 import android.os.RegistrantList;
35 import android.os.storage.StorageManager;
36 import android.preference.PreferenceManager;
37 import android.sysprop.TelephonyProperties;
38 import android.telephony.CarrierConfigManager;
39 import android.telephony.SubscriptionManager;
40 import android.telephony.TelephonyManager;
41 import android.telephony.UiccCardInfo;
42 import android.text.TextUtils;
43 import android.util.LocalLog;
44 
45 import com.android.internal.annotations.VisibleForTesting;
46 import com.android.internal.telephony.CommandException;
47 import com.android.internal.telephony.CommandsInterface;
48 import com.android.internal.telephony.IccCardConstants;
49 import com.android.internal.telephony.PhoneConfigurationManager;
50 import com.android.internal.telephony.PhoneConstants;
51 import com.android.internal.telephony.PhoneFactory;
52 import com.android.internal.telephony.RadioConfig;
53 import com.android.internal.telephony.SubscriptionInfoUpdater;
54 import com.android.internal.telephony.uicc.euicc.EuiccCard;
55 import com.android.internal.telephony.util.TelephonyUtils;
56 import com.android.telephony.Rlog;
57 
58 import java.io.FileDescriptor;
59 import java.io.PrintWriter;
60 import java.util.ArrayList;
61 import java.util.Arrays;
62 import java.util.HashSet;
63 import java.util.Set;
64 
65 /**
66  * This class is responsible for keeping all knowledge about
67  * Universal Integrated Circuit Card (UICC), also know as SIM's,
68  * in the system. It is also used as API to get appropriate
69  * applications to pass them to phone and service trackers.
70  *
71  * UiccController is created with the call to make() function.
72  * UiccController is a singleton and make() must only be called once
73  * and throws an exception if called multiple times.
74  *
75  * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
76  * notifications. When such notification arrives UiccController will call
77  * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
78  * request appropriate tree of uicc objects will be created.
79  *
80  * Following is class diagram for uicc classes:
81  *
82  *                       UiccController
83  *                            #
84  *                            |
85  *                        UiccSlot[]
86  *                            #
87  *                            |
88  *                        UiccCard
89  *                            #
90  *                            |
91  *                       UiccProfile
92  *                          #   #
93  *                          |   ------------------
94  *                    UiccCardApplication    CatService
95  *                      #            #
96  *                      |            |
97  *                 IccRecords    IccFileHandler
98  *                 ^ ^ ^           ^ ^ ^ ^ ^
99  *    SIMRecords---- | |           | | | | ---SIMFileHandler
100  *    RuimRecords----- |           | | | ----RuimFileHandler
101  *    IsimUiccRecords---           | | -----UsimFileHandler
102  *                                 | ------CsimFileHandler
103  *                                 ----IsimFileHandler
104  *
105  * Legend: # stands for Composition
106  *         ^ stands for Generalization
107  *
108  * See also {@link com.android.internal.telephony.IccCard}
109  */
110 public class UiccController extends Handler {
111     private static final boolean DBG = true;
112     private static final boolean VDBG = false; //STOPSHIP if true
113     private static final String LOG_TAG = "UiccController";
114 
115     public static final int INVALID_SLOT_ID = -1;
116 
117     public static final int APP_FAM_3GPP =  1;
118     public static final int APP_FAM_3GPP2 = 2;
119     public static final int APP_FAM_IMS   = 3;
120 
121     private static final int EVENT_ICC_STATUS_CHANGED = 1;
122     private static final int EVENT_SLOT_STATUS_CHANGED = 2;
123     private static final int EVENT_GET_ICC_STATUS_DONE = 3;
124     private static final int EVENT_GET_SLOT_STATUS_DONE = 4;
125     private static final int EVENT_RADIO_ON = 5;
126     private static final int EVENT_RADIO_AVAILABLE = 6;
127     private static final int EVENT_RADIO_UNAVAILABLE = 7;
128     private static final int EVENT_SIM_REFRESH = 8;
129     private static final int EVENT_EID_READY = 9;
130     private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10;
131     // NOTE: any new EVENT_* values must be added to eventToString.
132 
133     // this needs to be here, because on bootup we dont know which index maps to which UiccSlot
134     @UnsupportedAppUsage
135     private CommandsInterface[] mCis;
136     @VisibleForTesting
137     public UiccSlot[] mUiccSlots;
138     private int[] mPhoneIdToSlotId;
139     private boolean mIsSlotStatusSupported = true;
140 
141     // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID).
142     // The array index is the card ID (int).
143     // This mapping exists to expose card-based functionality without exposing the EID, which is
144     // considered sensetive information.
145     // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For
146     // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty
147     private ArrayList<String> mCardStrings;
148 
149     // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID.
150     // When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC
151     // with the lowest slot index.
152     // If EID is not supported (e.g. on HAL version < 1.2), we set it to UNSUPPORTED_CARD_ID
153     private int mDefaultEuiccCardId;
154 
155     // Default Euicc Card ID used when the device is temporarily unable to read the EID (e.g. on HAL
156     // 1.2-1.3 if the eUICC is currently inactive). This value is only used within the
157     // UiccController and should be converted to UNSUPPORTED_CARD_ID when others ask.
158     // (This value is -3 because UNSUPPORTED_CARD_ID and UNINITIALIZED_CARD_ID are -1 and -2)
159     private static final int TEMPORARILY_UNSUPPORTED_CARD_ID = -3;
160 
161     // GSM SGP.02 section 2.2.2 states that the EID is always 32 digits long
162     private static final int EID_LENGTH = 32;
163 
164     // SharedPreference key for saving the known card strings (ICCIDs and EIDs) ordered by card ID
165     private static final String CARD_STRINGS = "card_strings";
166 
167     // Whether the device has an eUICC built in.
168     private boolean mHasBuiltInEuicc = false;
169 
170     // Whether the device has a currently active built in eUICC
171     private boolean mHasActiveBuiltInEuicc = false;
172 
173     // The physical slots which correspond to built-in eUICCs
174     private final int[] mEuiccSlots;
175 
176     // SharedPreferences key for saving the default euicc card ID
177     private static final String DEFAULT_CARD = "default_card";
178 
179     @UnsupportedAppUsage
180     private static final Object mLock = new Object();
181     @UnsupportedAppUsage
182     private static UiccController mInstance;
183     @VisibleForTesting
184     public static ArrayList<IccSlotStatus> sLastSlotStatus;
185 
186     @UnsupportedAppUsage
187     @VisibleForTesting
188     public Context mContext;
189 
190     protected RegistrantList mIccChangedRegistrants = new RegistrantList();
191 
192     private UiccStateChangedLauncher mLauncher;
193     private RadioConfig mRadioConfig;
194 
195     // LocalLog buffer to hold important SIM related events for debugging
196     private static LocalLog sLocalLog = new LocalLog(TelephonyUtils.IS_DEBUGGABLE ? 250 : 100);
197 
198     /**
199      * API to make UiccController singleton if not already created.
200      */
make(Context c)201     public static UiccController make(Context c) {
202         synchronized (mLock) {
203             if (mInstance != null) {
204                 throw new RuntimeException("UiccController.make() should only be called once");
205             }
206             mInstance = new UiccController(c);
207             return mInstance;
208         }
209     }
210 
UiccController(Context c)211     private UiccController(Context c) {
212         if (DBG) log("Creating UiccController");
213         mContext = c;
214         mCis = PhoneFactory.getCommandsInterfaces();
215         int numPhysicalSlots = c.getResources().getInteger(
216                 com.android.internal.R.integer.config_num_physical_slots);
217         numPhysicalSlots = TelephonyProperties.sim_slots_count().orElse(numPhysicalSlots);
218         if (DBG) {
219             logWithLocalLog("config_num_physical_slots = " + numPhysicalSlots);
220         }
221         // Minimum number of physical slot count should be equals to or greater than phone count,
222         // if it is less than phone count use phone count as physical slot count.
223         if (numPhysicalSlots < mCis.length) {
224             numPhysicalSlots = mCis.length;
225         }
226 
227         mUiccSlots = new UiccSlot[numPhysicalSlots];
228         mPhoneIdToSlotId = new int[mCis.length];
229         Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID);
230         if (VDBG) logPhoneIdToSlotIdMapping();
231         mRadioConfig = RadioConfig.getInstance(mContext);
232         mRadioConfig.registerForSimSlotStatusChanged(this, EVENT_SLOT_STATUS_CHANGED, null);
233         for (int i = 0; i < mCis.length; i++) {
234             mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);
235 
236             if (!StorageManager.inCryptKeeperBounce()) {
237                 mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
238             } else {
239                 mCis[i].registerForOn(this, EVENT_RADIO_ON, i);
240             }
241 
242             mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
243             mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
244         }
245 
246         mLauncher = new UiccStateChangedLauncher(c, this);
247         mCardStrings = loadCardStrings();
248         mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
249 
250         mEuiccSlots = mContext.getResources()
251                 .getIntArray(com.android.internal.R.array.non_removable_euicc_slots);
252         mHasBuiltInEuicc = hasBuiltInEuicc();
253 
254         PhoneConfigurationManager.registerForMultiSimConfigChange(
255                 this, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
256     }
257 
258     /**
259      * Given the slot index, return the phone ID, or -1 if no phone is associated with the given
260      * slot.
261      * @param slotId the slot index to check
262      * @return the associated phone ID or -1
263      */
getPhoneIdFromSlotId(int slotId)264     public int getPhoneIdFromSlotId(int slotId) {
265         for (int i = 0; i < mPhoneIdToSlotId.length; i++) {
266             if (mPhoneIdToSlotId[i] == slotId) {
267                 return i;
268             }
269         }
270         return -1;
271     }
272 
273     /**
274      * Return the physical slot id associated with the given phoneId, or INVALID_SLOT_ID.
275      * @param phoneId the phoneId to check
276      */
getSlotIdFromPhoneId(int phoneId)277     public int getSlotIdFromPhoneId(int phoneId) {
278         try {
279             return mPhoneIdToSlotId[phoneId];
280         } catch (ArrayIndexOutOfBoundsException e) {
281             return INVALID_SLOT_ID;
282         }
283     }
284 
285     @UnsupportedAppUsage
getInstance()286     public static UiccController getInstance() {
287         synchronized (mLock) {
288             if (mInstance == null) {
289                 throw new RuntimeException(
290                         "UiccController.getInstance can't be called before make()");
291             }
292             return mInstance;
293         }
294     }
295 
296     @UnsupportedAppUsage
getUiccCard(int phoneId)297     public UiccCard getUiccCard(int phoneId) {
298         synchronized (mLock) {
299             return getUiccCardForPhone(phoneId);
300         }
301     }
302 
303     /**
304      * API to get UiccCard corresponding to given physical slot index
305      * @param slotId index of physical slot on the device
306      * @return UiccCard object corresponting to given physical slot index; null if card is
307      * absent
308      */
getUiccCardForSlot(int slotId)309     public UiccCard getUiccCardForSlot(int slotId) {
310         synchronized (mLock) {
311             UiccSlot uiccSlot = getUiccSlot(slotId);
312             if (uiccSlot != null) {
313                 return uiccSlot.getUiccCard();
314             }
315             return null;
316         }
317     }
318 
319     /**
320      * API to get UiccCard corresponding to given phone id
321      * @return UiccCard object corresponding to given phone id; null if there is no card present for
322      * the phone id
323      */
getUiccCardForPhone(int phoneId)324     public UiccCard getUiccCardForPhone(int phoneId) {
325         synchronized (mLock) {
326             if (isValidPhoneIndex(phoneId)) {
327                 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
328                 if (uiccSlot != null) {
329                     return uiccSlot.getUiccCard();
330                 }
331             }
332             return null;
333         }
334     }
335 
336     /**
337      * API to get UiccProfile corresponding to given phone id
338      * @return UiccProfile object corresponding to given phone id; null if there is no card/profile
339      * present for the phone id
340      */
getUiccProfileForPhone(int phoneId)341     public UiccProfile getUiccProfileForPhone(int phoneId) {
342         synchronized (mLock) {
343             if (isValidPhoneIndex(phoneId)) {
344                 UiccCard uiccCard = getUiccCardForPhone(phoneId);
345                 return uiccCard != null ? uiccCard.getUiccProfile() : null;
346             }
347             return null;
348         }
349     }
350 
351     /**
352      * API to get all the UICC slots.
353      * @return UiccSlots array.
354      */
getUiccSlots()355     public UiccSlot[] getUiccSlots() {
356         synchronized (mLock) {
357             return mUiccSlots;
358         }
359     }
360 
361     /** Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive. */
switchSlots(int[] physicalSlots, Message response)362     public void switchSlots(int[] physicalSlots, Message response) {
363         logWithLocalLog("switchSlots: " + Arrays.toString(physicalSlots));
364         mRadioConfig.setSimSlotsMapping(physicalSlots, response);
365     }
366 
367     /**
368      * API to get UiccSlot object for a specific physical slot index on the device
369      * @return UiccSlot object for the given physical slot index
370      */
getUiccSlot(int slotId)371     public UiccSlot getUiccSlot(int slotId) {
372         synchronized (mLock) {
373             if (isValidSlotIndex(slotId)) {
374                 return mUiccSlots[slotId];
375             }
376             return null;
377         }
378     }
379 
380     /**
381      * API to get UiccSlot object for a given phone id
382      * @return UiccSlot object for the given phone id
383      */
getUiccSlotForPhone(int phoneId)384     public UiccSlot getUiccSlotForPhone(int phoneId) {
385         synchronized (mLock) {
386             if (isValidPhoneIndex(phoneId)) {
387                 int slotId = getSlotIdFromPhoneId(phoneId);
388                 if (isValidSlotIndex(slotId)) {
389                     return mUiccSlots[slotId];
390                 }
391             }
392             return null;
393         }
394     }
395 
396     /**
397      * API to get UiccSlot object for a given cardId
398      * @param cardId Identifier for a SIM. This can be an ICCID, or an EID in case of an eSIM.
399      * @return int Index of UiccSlot for the given cardId if one is found, {@link #INVALID_SLOT_ID}
400      * otherwise
401      */
getUiccSlotForCardId(String cardId)402     public int getUiccSlotForCardId(String cardId) {
403         synchronized (mLock) {
404             // first look up based on cardId
405             for (int idx = 0; idx < mUiccSlots.length; idx++) {
406                 if (mUiccSlots[idx] != null) {
407                     UiccCard uiccCard = mUiccSlots[idx].getUiccCard();
408                     if (uiccCard != null && cardId.equals(uiccCard.getCardId())) {
409                         return idx;
410                     }
411                 }
412             }
413             // if a match is not found, do a lookup based on ICCID
414             for (int idx = 0; idx < mUiccSlots.length; idx++) {
415                 if (mUiccSlots[idx] != null && cardId.equals(mUiccSlots[idx].getIccId())) {
416                     return idx;
417                 }
418             }
419             return INVALID_SLOT_ID;
420         }
421     }
422 
423     // Easy to use API
424     @UnsupportedAppUsage
getIccRecords(int phoneId, int family)425     public IccRecords getIccRecords(int phoneId, int family) {
426         synchronized (mLock) {
427             UiccCardApplication app = getUiccCardApplication(phoneId, family);
428             if (app != null) {
429                 return app.getIccRecords();
430             }
431             return null;
432         }
433     }
434 
435     // Easy to use API
436     @UnsupportedAppUsage
getIccFileHandler(int phoneId, int family)437     public IccFileHandler getIccFileHandler(int phoneId, int family) {
438         synchronized (mLock) {
439             UiccCardApplication app = getUiccCardApplication(phoneId, family);
440             if (app != null) {
441                 return app.getIccFileHandler();
442             }
443             return null;
444         }
445     }
446 
447 
448     //Notifies when card status changes
449     @UnsupportedAppUsage
registerForIccChanged(Handler h, int what, Object obj)450     public void registerForIccChanged(Handler h, int what, Object obj) {
451         synchronized (mLock) {
452             mIccChangedRegistrants.addUnique(h, what, obj);
453         }
454         //Notify registrant right after registering, so that it will get the latest ICC status,
455         //otherwise which may not happen until there is an actual change in ICC status.
456         Message.obtain(h, what, new AsyncResult(obj, null, null)).sendToTarget();
457     }
458 
unregisterForIccChanged(Handler h)459     public void unregisterForIccChanged(Handler h) {
460         synchronized (mLock) {
461             mIccChangedRegistrants.remove(h);
462         }
463     }
464 
465     @Override
handleMessage(Message msg)466     public void handleMessage (Message msg) {
467         synchronized (mLock) {
468             Integer phoneId = getCiIndex(msg);
469             String eventName = eventToString(msg.what);
470 
471             if (phoneId < 0 || phoneId >= mCis.length) {
472                 Rlog.e(LOG_TAG, "Invalid phoneId : " + phoneId + " received with event "
473                         + eventName);
474                 return;
475             }
476 
477             logWithLocalLog("handleMessage: Received " + eventName + " for phoneId " + phoneId);
478 
479             AsyncResult ar = (AsyncResult)msg.obj;
480             switch (msg.what) {
481                 case EVENT_ICC_STATUS_CHANGED:
482                     if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
483                     mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
484                             phoneId));
485                     break;
486                 case EVENT_RADIO_AVAILABLE:
487                 case EVENT_RADIO_ON:
488                     if (DBG) {
489                         log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "
490                                 + "getIccCardStatus");
491                     }
492                     mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
493                             phoneId));
494                     // slot status should be the same on all RILs; request it only for phoneId 0
495                     if (phoneId == 0) {
496                         if (DBG) {
497                             log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, "
498                                     + "calling getIccSlotsStatus");
499                         }
500                         mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,
501                                 phoneId));
502                     }
503                     break;
504                 case EVENT_GET_ICC_STATUS_DONE:
505                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
506                     onGetIccCardStatusDone(ar, phoneId);
507                     break;
508                 case EVENT_SLOT_STATUS_CHANGED:
509                 case EVENT_GET_SLOT_STATUS_DONE:
510                     if (DBG) {
511                         log("Received EVENT_SLOT_STATUS_CHANGED or EVENT_GET_SLOT_STATUS_DONE");
512                     }
513                     onGetSlotStatusDone(ar);
514                     break;
515                 case EVENT_RADIO_UNAVAILABLE:
516                     if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
517                     UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
518                     if (uiccSlot != null) {
519                         uiccSlot.onRadioStateUnavailable();
520                     }
521                     mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, phoneId, null));
522                     break;
523                 case EVENT_SIM_REFRESH:
524                     if (DBG) log("Received EVENT_SIM_REFRESH");
525                     onSimRefresh(ar, phoneId);
526                     break;
527                 case EVENT_EID_READY:
528                     if (DBG) log("Received EVENT_EID_READY");
529                     onEidReady(ar, phoneId);
530                     break;
531                 case EVENT_MULTI_SIM_CONFIG_CHANGED:
532                     if (DBG) log("Received EVENT_MULTI_SIM_CONFIG_CHANGED");
533                     int activeModemCount = (int) ((AsyncResult) msg.obj).result;
534                     onMultiSimConfigChanged(activeModemCount);
535                     break;
536                 default:
537                     Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
538                     break;
539             }
540         }
541     }
542 
onMultiSimConfigChanged(int newActiveModemCount)543     private void onMultiSimConfigChanged(int newActiveModemCount) {
544         int prevActiveModemCount = mCis.length;
545         mCis = PhoneFactory.getCommandsInterfaces();
546 
547         logWithLocalLog("onMultiSimConfigChanged: prevActiveModemCount " + prevActiveModemCount
548                 + ", newActiveModemCount " + newActiveModemCount);
549 
550         // Resize array.
551         mPhoneIdToSlotId = copyOf(mPhoneIdToSlotId, newActiveModemCount);
552 
553         // Register for new active modem for ss -> ds switch.
554         // For ds -> ss switch, there's no need to unregister as the mCis should unregister
555         // everything itself.
556         for (int i = prevActiveModemCount; i < newActiveModemCount; i++) {
557             mPhoneIdToSlotId[i] = INVALID_SLOT_ID;
558             mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);
559 
560             /*
561              * To support FDE (deprecated), additional check is needed:
562              *
563              * if (!StorageManager.inCryptKeeperBounce()) {
564              *     mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
565              * } else {
566              *     mCis[i].registerForOn(this, EVENT_RADIO_ON, i);
567              * }
568              */
569             mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
570 
571             mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
572             mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
573         }
574     }
575 
getCiIndex(Message msg)576     private Integer getCiIndex(Message msg) {
577         AsyncResult ar;
578         Integer index = new Integer(PhoneConstants.DEFAULT_SLOT_INDEX);
579 
580         /*
581          * The events can be come in two ways. By explicitly sending it using
582          * sendMessage, in this case the user object passed is msg.obj and from
583          * the CommandsInterface, in this case the user object is msg.obj.userObj
584          */
585         if (msg != null) {
586             if (msg.obj != null && msg.obj instanceof Integer) {
587                 index = (Integer)msg.obj;
588             } else if(msg.obj != null && msg.obj instanceof AsyncResult) {
589                 ar = (AsyncResult)msg.obj;
590                 if (ar.userObj != null && ar.userObj instanceof Integer) {
591                     index = (Integer)ar.userObj;
592                 }
593             }
594         }
595         return index;
596     }
597 
eventToString(int event)598     private static String eventToString(int event) {
599         switch (event) {
600             case EVENT_ICC_STATUS_CHANGED: return "ICC_STATUS_CHANGED";
601             case EVENT_SLOT_STATUS_CHANGED: return "SLOT_STATUS_CHANGED";
602             case EVENT_GET_ICC_STATUS_DONE: return "GET_ICC_STATUS_DONE";
603             case EVENT_GET_SLOT_STATUS_DONE: return "GET_SLOT_STATUS_DONE";
604             case EVENT_RADIO_ON: return "RADIO_ON";
605             case EVENT_RADIO_AVAILABLE: return "RADIO_AVAILABLE";
606             case EVENT_RADIO_UNAVAILABLE: return "RADIO_UNAVAILABLE";
607             case EVENT_SIM_REFRESH: return "SIM_REFRESH";
608             case EVENT_EID_READY: return "EID_READY";
609             case EVENT_MULTI_SIM_CONFIG_CHANGED: return "MULTI_SIM_CONFIG_CHANGED";
610             default: return "UNKNOWN(" + event + ")";
611         }
612     }
613 
614     // Easy to use API
615     @UnsupportedAppUsage
getUiccCardApplication(int phoneId, int family)616     public UiccCardApplication getUiccCardApplication(int phoneId, int family) {
617         synchronized (mLock) {
618             UiccCard uiccCard = getUiccCardForPhone(phoneId);
619             if (uiccCard != null) {
620                 return uiccCard.getApplication(family);
621             }
622             return null;
623         }
624     }
625 
getIccStateIntentString(IccCardConstants.State state)626     static String getIccStateIntentString(IccCardConstants.State state) {
627         switch (state) {
628             case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
629             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
630             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
631             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
632             case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
633             case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
634             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
635             case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
636             case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED;
637             case LOADED: return IccCardConstants.INTENT_VALUE_ICC_LOADED;
638             default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
639         }
640     }
641 
updateInternalIccStateForInactiveSlot( Context context, int prevActivePhoneId, String iccId)642     static void updateInternalIccStateForInactiveSlot(
643             Context context, int prevActivePhoneId, String iccId) {
644         if (SubscriptionManager.isValidPhoneId(prevActivePhoneId)) {
645             // Mark SIM state as ABSENT on previously phoneId.
646             TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
647                     Context.TELEPHONY_SERVICE);
648             telephonyManager.setSimStateForPhone(prevActivePhoneId,
649                     IccCardConstants.State.ABSENT.toString());
650         }
651 
652         SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater();
653         if (subInfoUpdator != null) {
654             subInfoUpdator.updateInternalIccStateForInactiveSlot(prevActivePhoneId, iccId);
655         } else {
656             Rlog.e(LOG_TAG, "subInfoUpdate is null.");
657         }
658     }
659 
updateInternalIccState(Context context, IccCardConstants.State state, String reason, int phoneId)660     static void updateInternalIccState(Context context, IccCardConstants.State state, String reason,
661             int phoneId) {
662         TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
663                 Context.TELEPHONY_SERVICE);
664         telephonyManager.setSimStateForPhone(phoneId, state.toString());
665 
666         SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater();
667         if (subInfoUpdator != null) {
668             subInfoUpdator.updateInternalIccState(getIccStateIntentString(state), reason, phoneId);
669         } else {
670             Rlog.e(LOG_TAG, "subInfoUpdate is null.");
671         }
672     }
673 
onGetIccCardStatusDone(AsyncResult ar, Integer index)674     private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
675         if (ar.exception != null) {
676             Rlog.e(LOG_TAG,"Error getting ICC status. "
677                     + "RIL_REQUEST_GET_ICC_STATUS should "
678                     + "never return an error", ar.exception);
679             return;
680         }
681         if (!isValidPhoneIndex(index)) {
682             Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
683             return;
684         }
685 
686         IccCardStatus status = (IccCardStatus)ar.result;
687 
688         logWithLocalLog("onGetIccCardStatusDone: phoneId " + index + " IccCardStatus: " + status);
689 
690         int slotId = status.physicalSlotIndex;
691         if (VDBG) log("onGetIccCardStatusDone: phoneId " + index + " physicalSlotIndex " + slotId);
692         if (slotId == INVALID_SLOT_ID) {
693             slotId = index;
694         }
695 
696         if (eidIsNotSupported(status)) {
697             // we will never get EID from the HAL, so set mDefaultEuiccCardId to UNSUPPORTED_CARD_ID
698             if (DBG) log("eid is not supported");
699             mDefaultEuiccCardId = UNSUPPORTED_CARD_ID;
700         }
701         mPhoneIdToSlotId[index] = slotId;
702 
703         if (VDBG) logPhoneIdToSlotIdMapping();
704 
705         if (mUiccSlots[slotId] == null) {
706             if (VDBG) {
707                 log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = "
708                         + mUiccSlots.length);
709             }
710             mUiccSlots[slotId] = new UiccSlot(mContext, true);
711         }
712 
713         mUiccSlots[slotId].update(mCis[index], status, index, slotId);
714 
715         UiccCard card = mUiccSlots[slotId].getUiccCard();
716         if (card == null) {
717             if (DBG) log("mUiccSlots[" + slotId + "] has no card. Notifying IccChangedRegistrants");
718             mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
719             return;
720         }
721 
722         String cardString = null;
723         boolean isEuicc = mUiccSlots[slotId].isEuicc();
724         if (isEuicc) {
725             cardString = ((EuiccCard) card).getEid();
726         } else {
727             cardString = card.getIccId();
728         }
729 
730         if (cardString != null) {
731             addCardId(cardString);
732         }
733 
734         // EID is unpopulated if Radio HAL < 1.4 (RadioConfig < 1.2)
735         // If so, just register for EID loaded and skip this stuff
736         if (isEuicc && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) {
737             if (cardString == null) {
738                 ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index);
739             } else {
740                 // If we know the EID from IccCardStatus, just use it to set mDefaultEuiccCardId if
741                 // it's not already set.
742                 // This is needed in cases where slot status doesn't include EID, and we don't want
743                 // to register for EID from APDU because we already know cardString from a previous
744                 // APDU
745                 if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
746                         || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
747                     mDefaultEuiccCardId = convertToPublicCardId(cardString);
748                     logWithLocalLog("IccCardStatus eid=" + cardString + " slot=" + slotId
749                             + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
750                 }
751             }
752         }
753 
754         if (DBG) log("Notifying IccChangedRegistrants");
755         mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
756     }
757 
758     /**
759      * Returns true if EID is not supproted.
760      */
eidIsNotSupported(IccCardStatus status)761     private boolean eidIsNotSupported(IccCardStatus status) {
762         // if card status does not contain slot ID, we know we are on HAL < 1.2, so EID will never
763         // be available
764         return status.physicalSlotIndex == INVALID_SLOT_ID;
765     }
766 
767     /**
768      * Add a cardString to mCardStrings. If this is an ICCID, trailing Fs will be automatically
769      * stripped.
770      */
addCardId(String cardString)771     private void addCardId(String cardString) {
772         if (TextUtils.isEmpty(cardString)) {
773             return;
774         }
775         if (cardString.length() < EID_LENGTH) {
776             cardString = IccUtils.stripTrailingFs(cardString);
777         }
778         if (!mCardStrings.contains(cardString)) {
779             mCardStrings.add(cardString);
780             saveCardStrings();
781         }
782     }
783 
784     /**
785      * Converts an integer cardId (public card ID) to a card string.
786      * @param cardId to convert
787      * @return cardString, or null if the cardId is not valid
788      */
convertToCardString(int cardId)789     public String convertToCardString(int cardId) {
790         if (cardId < 0 || cardId >= mCardStrings.size()) {
791             log("convertToCardString: cardId " + cardId + " is not valid");
792             return null;
793         }
794         return mCardStrings.get(cardId);
795     }
796 
797     /**
798      * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId.
799      * If the given cardString is an ICCID, trailing Fs will be automatically stripped before trying
800      * to match to a card ID.
801      *
802      * @return the matching cardId, or UNINITIALIZED_CARD_ID if the card string does not map to a
803      * currently loaded cardId, or UNSUPPORTED_CARD_ID if the device does not support card IDs
804      */
convertToPublicCardId(String cardString)805     public int convertToPublicCardId(String cardString) {
806         if (mDefaultEuiccCardId == UNSUPPORTED_CARD_ID) {
807             // even if cardString is not an EID, if EID is not supported (e.g. HAL < 1.2) we can't
808             // guarentee a working card ID implementation, so return UNSUPPORTED_CARD_ID
809             return UNSUPPORTED_CARD_ID;
810         }
811         if (TextUtils.isEmpty(cardString)) {
812             return UNINITIALIZED_CARD_ID;
813         }
814 
815         if (cardString.length() < EID_LENGTH) {
816             cardString = IccUtils.stripTrailingFs(cardString);
817         }
818         int id = mCardStrings.indexOf(cardString);
819         if (id == -1) {
820             return UNINITIALIZED_CARD_ID;
821         } else {
822             return id;
823         }
824     }
825 
826     /**
827      * Returns the UiccCardInfo of all currently inserted UICCs and embedded eUICCs.
828      */
getAllUiccCardInfos()829     public ArrayList<UiccCardInfo> getAllUiccCardInfos() {
830         ArrayList<UiccCardInfo> infos = new ArrayList<>();
831         for (int slotIndex = 0; slotIndex < mUiccSlots.length; slotIndex++) {
832             final UiccSlot slot = mUiccSlots[slotIndex];
833             if (slot == null) continue;
834             boolean isEuicc = slot.isEuicc();
835             String eid = null;
836             UiccCard card = slot.getUiccCard();
837             String iccid = null;
838             int cardId = UNINITIALIZED_CARD_ID;
839             boolean isRemovable = slot.isRemovable();
840 
841             // first we try to populate UiccCardInfo using the UiccCard, but if it doesn't exist
842             // (e.g. the slot is for an inactive eUICC) then we try using the UiccSlot.
843             if (card != null) {
844                 iccid = card.getIccId();
845                 if (isEuicc) {
846                     eid = ((EuiccCard) card).getEid();
847                     cardId = convertToPublicCardId(eid);
848                 } else {
849                     // leave eid null if the UICC is not embedded
850                     cardId = convertToPublicCardId(iccid);
851                 }
852             } else {
853                 iccid = slot.getIccId();
854                 // Fill in the fields we can
855                 if (!isEuicc && !TextUtils.isEmpty(iccid)) {
856                     cardId = convertToPublicCardId(iccid);
857                 }
858             }
859             UiccCardInfo info = new UiccCardInfo(isEuicc, cardId, eid,
860                     IccUtils.stripTrailingFs(iccid), slotIndex, isRemovable);
861             infos.add(info);
862         }
863         return infos;
864     }
865 
866     /**
867      * Get the card ID of the default eUICC.
868      */
getCardIdForDefaultEuicc()869     public int getCardIdForDefaultEuicc() {
870         if (mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
871             return UNSUPPORTED_CARD_ID;
872         }
873         return mDefaultEuiccCardId;
874     }
875 
loadCardStrings()876     private ArrayList<String> loadCardStrings() {
877         String cardStrings =
878                 PreferenceManager.getDefaultSharedPreferences(mContext).getString(CARD_STRINGS, "");
879         if (TextUtils.isEmpty(cardStrings)) {
880             // just return an empty list, since String.split would return the list { "" }
881             return new ArrayList<String>();
882         }
883         return new ArrayList<String>(Arrays.asList(cardStrings.split(",")));
884     }
885 
saveCardStrings()886     private void saveCardStrings() {
887         SharedPreferences.Editor editor =
888                 PreferenceManager.getDefaultSharedPreferences(mContext).edit();
889         editor.putString(CARD_STRINGS, TextUtils.join(",", mCardStrings));
890         editor.commit();
891     }
892 
onGetSlotStatusDone(AsyncResult ar)893     private synchronized void onGetSlotStatusDone(AsyncResult ar) {
894         if (!mIsSlotStatusSupported) {
895             if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false");
896             return;
897         }
898         Throwable e = ar.exception;
899         if (e != null) {
900             if (!(e instanceof CommandException) || ((CommandException) e).getCommandError()
901                     != CommandException.Error.REQUEST_NOT_SUPPORTED) {
902                 // this is not expected; there should be no exception other than
903                 // REQUEST_NOT_SUPPORTED
904                 logeWithLocalLog("Unexpected error getting slot status: " + ar.exception);
905             } else {
906                 // REQUEST_NOT_SUPPORTED
907                 logWithLocalLog("onGetSlotStatusDone: request not supported; marking "
908                         + "mIsSlotStatusSupported to false");
909                 mIsSlotStatusSupported = false;
910             }
911             return;
912         }
913 
914         ArrayList<IccSlotStatus> status = (ArrayList<IccSlotStatus>) ar.result;
915 
916         if (!slotStatusChanged(status)) {
917             log("onGetSlotStatusDone: No change in slot status");
918             return;
919         }
920         logWithLocalLog("onGetSlotStatusDone: " + status);
921 
922         sLastSlotStatus = status;
923 
924         int numActiveSlots = 0;
925         boolean isDefaultEuiccCardIdSet = false;
926         boolean anyEuiccIsActive = false;
927         mHasActiveBuiltInEuicc = false;
928 
929         int numSlots = status.size();
930         if (mUiccSlots.length < numSlots) {
931             logeWithLocalLog("The number of the physical slots reported " + numSlots
932                     + " is greater than the expectation " + mUiccSlots.length);
933             numSlots = mUiccSlots.length;
934         }
935 
936         for (int i = 0; i < numSlots; i++) {
937             IccSlotStatus iss = status.get(i);
938             boolean isActive = (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_ACTIVE);
939             if (isActive) {
940                 numActiveSlots++;
941 
942                 // sanity check: logicalSlotIndex should be valid for an active slot
943                 if (!isValidPhoneIndex(iss.logicalSlotIndex)) {
944                     Rlog.e(LOG_TAG, "Skipping slot " + i + " as phone " + iss.logicalSlotIndex
945                                + " is not available to communicate with this slot");
946                 } else {
947                     mPhoneIdToSlotId[iss.logicalSlotIndex] = i;
948                 }
949             }
950 
951             if (mUiccSlots[i] == null) {
952                 if (VDBG) {
953                     log("Creating mUiccSlot[" + i + "]; mUiccSlots.length = " + mUiccSlots.length);
954                 }
955                 mUiccSlots[i] = new UiccSlot(mContext, isActive);
956             }
957 
958             if (!isValidPhoneIndex(iss.logicalSlotIndex)) {
959                 mUiccSlots[i].update(null, iss, i /* slotIndex */);
960             } else {
961                 mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss,
962                         i /* slotIndex */);
963             }
964 
965             if (mUiccSlots[i].isEuicc()) {
966                 if (isActive) {
967                     anyEuiccIsActive = true;
968 
969                     if (isBuiltInEuiccSlot(i)) {
970                         mHasActiveBuiltInEuicc = true;
971                     }
972                 }
973                 String eid = iss.eid;
974                 if (TextUtils.isEmpty(eid)) {
975                     // iss.eid is not populated on HAL<1.4
976                     continue;
977                 }
978 
979                 addCardId(eid);
980 
981                 // whenever slot status is received, set default card to the non-removable eUICC
982                 // with the lowest slot index.
983                 if (!mUiccSlots[i].isRemovable() && !isDefaultEuiccCardIdSet) {
984                     isDefaultEuiccCardIdSet = true;
985                     mDefaultEuiccCardId = convertToPublicCardId(eid);
986                     logWithLocalLog("Using eid=" + eid + " in slot=" + i
987                             + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId);
988                 }
989             }
990         }
991 
992         if (!mHasActiveBuiltInEuicc && !isDefaultEuiccCardIdSet) {
993             // if there are no active built-in eUICCs, then consider setting a removable eUICC to
994             // the default.
995             // Note that on HAL<1.2, it's possible that a built-in eUICC exists, but does not
996             // correspond to any slot in mUiccSlots. This logic is still safe in that case because
997             // SlotStatus is only for HAL >= 1.2
998             for (int i = 0; i < numSlots; i++) {
999                 if (mUiccSlots[i].isEuicc()) {
1000                     String eid = status.get(i).eid;
1001                     if (!TextUtils.isEmpty(eid)) {
1002                         isDefaultEuiccCardIdSet = true;
1003                         mDefaultEuiccCardId = convertToPublicCardId(eid);
1004                         logWithLocalLog("Using eid=" + eid + " from removable eUICC in slot="
1005                                 + i + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1006                         break;
1007                     }
1008                 }
1009             }
1010         }
1011 
1012         if (mHasBuiltInEuicc && !anyEuiccIsActive && !isDefaultEuiccCardIdSet) {
1013             logWithLocalLog(
1014                     "onGetSlotStatusDone: mDefaultEuiccCardId=TEMPORARILY_UNSUPPORTED_CARD_ID");
1015             isDefaultEuiccCardIdSet = true;
1016             mDefaultEuiccCardId = TEMPORARILY_UNSUPPORTED_CARD_ID;
1017         }
1018 
1019 
1020         if (!isDefaultEuiccCardIdSet) {
1021             if (mDefaultEuiccCardId >= 0) {
1022                 // if mDefaultEuiccCardId has already been set to an actual eUICC,
1023                 // don't overwrite mDefaultEuiccCardId unless that eUICC is no longer inserted
1024                 boolean defaultEuiccCardIdIsStillInserted = false;
1025                 String cardString = mCardStrings.get(mDefaultEuiccCardId);
1026                 for (UiccSlot slot : mUiccSlots) {
1027                     if (slot.getUiccCard() == null) {
1028                         continue;
1029                     }
1030                     if (cardString.equals(
1031                             IccUtils.stripTrailingFs(slot.getUiccCard().getCardId()))) {
1032                         defaultEuiccCardIdIsStillInserted = true;
1033                     }
1034                 }
1035                 if (!defaultEuiccCardIdIsStillInserted) {
1036                     logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId="
1037                             + mDefaultEuiccCardId
1038                             + " is no longer inserted. Setting mDefaultEuiccCardId=UNINITIALIZED");
1039                     mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1040                 }
1041             } else {
1042                 // no known eUICCs at all (it's possible that an eUICC is inserted and we just don't
1043                 // know it's EID)
1044                 logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId=UNINITIALIZED");
1045                 mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1046             }
1047         }
1048 
1049         if (VDBG) logPhoneIdToSlotIdMapping();
1050 
1051         // sanity check: number of active slots should be valid
1052         if (numActiveSlots != mPhoneIdToSlotId.length) {
1053             Rlog.e(LOG_TAG, "Number of active slots " + numActiveSlots
1054                        + " does not match the number of Phones" + mPhoneIdToSlotId.length);
1055         }
1056 
1057         // sanity check: slotIds should be unique in mPhoneIdToSlotId
1058         Set<Integer> slotIds = new HashSet<>();
1059         for (int slotId : mPhoneIdToSlotId) {
1060             if (slotIds.contains(slotId)) {
1061                 throw new RuntimeException("slotId " + slotId + " mapped to multiple phoneIds");
1062             }
1063             slotIds.add(slotId);
1064         }
1065 
1066         // broadcast slot status changed
1067         final BroadcastOptions options = BroadcastOptions.makeBasic();
1068         options.setBackgroundActivityStartsAllowed(true);
1069         Intent intent = new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED);
1070         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1071         mContext.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1072                 options.toBundle());
1073     }
1074 
slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList)1075     private boolean slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList) {
1076         if (sLastSlotStatus == null || sLastSlotStatus.size() != slotStatusList.size()) {
1077             return true;
1078         }
1079         for (IccSlotStatus iccSlotStatus : slotStatusList) {
1080             if (!sLastSlotStatus.contains(iccSlotStatus)) {
1081                 return true;
1082             }
1083         }
1084         return false;
1085     }
1086 
logPhoneIdToSlotIdMapping()1087     private void logPhoneIdToSlotIdMapping() {
1088         log("mPhoneIdToSlotId mapping:");
1089         for (int i = 0; i < mPhoneIdToSlotId.length; i++) {
1090             log("    phoneId " + i + " slotId " + mPhoneIdToSlotId[i]);
1091         }
1092     }
1093 
onSimRefresh(AsyncResult ar, Integer index)1094     private void onSimRefresh(AsyncResult ar, Integer index) {
1095         if (ar.exception != null) {
1096             Rlog.e(LOG_TAG, "onSimRefresh: Sim REFRESH with exception: " + ar.exception);
1097             return;
1098         }
1099 
1100         if (!isValidPhoneIndex(index)) {
1101             Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index);
1102             return;
1103         }
1104 
1105         IccRefreshResponse resp = (IccRefreshResponse) ar.result;
1106         logWithLocalLog("onSimRefresh: index " + index + ", " + resp);
1107 
1108         if (resp == null) {
1109             Rlog.e(LOG_TAG, "onSimRefresh: received without input");
1110             return;
1111         }
1112 
1113         UiccCard uiccCard = getUiccCardForPhone(index);
1114         if (uiccCard == null) {
1115             Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index);
1116             return;
1117         }
1118 
1119         boolean changed = false;
1120         switch(resp.refreshResult) {
1121             // Reset the required apps when we know about the refresh so that
1122             // anyone interested does not get stale state.
1123             case IccRefreshResponse.REFRESH_RESULT_RESET:
1124                 changed = uiccCard.resetAppWithAid(resp.aid, true /* reset */);
1125                 break;
1126             case IccRefreshResponse.REFRESH_RESULT_INIT:
1127                 // don't dispose CatService on SIM REFRESH of type INIT
1128                 changed = uiccCard.resetAppWithAid(resp.aid, false /* initialize */);
1129                 break;
1130             default:
1131                 return;
1132         }
1133 
1134         if (changed && resp.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
1135             // If there is any change on RESET, reset carrier config as well. From carrier config
1136             // perspective, this is treated the same as sim state unknown
1137             CarrierConfigManager configManager = (CarrierConfigManager)
1138                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1139             configManager.updateConfigForPhoneId(index, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
1140 
1141             boolean requirePowerOffOnSimRefreshReset = mContext.getResources().getBoolean(
1142                     com.android.internal.R.bool.config_requireRadioPowerOffOnSimRefreshReset);
1143             if (requirePowerOffOnSimRefreshReset) {
1144                 mCis[index].setRadioPower(false, null);
1145             }
1146         }
1147 
1148         // The card status could have changed. Get the latest state.
1149         mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
1150     }
1151 
1152     // for HAL 1.2-1.3 we register for EID ready, set mCardStrings and mDefaultEuiccCardId here.
1153     // Note that if there are multiple eUICCs on HAL 1.2-1.3, the default eUICC is the one whose EID
1154     // is first loaded
onEidReady(AsyncResult ar, Integer index)1155     private void onEidReady(AsyncResult ar, Integer index) {
1156         if (ar.exception != null) {
1157             Rlog.e(LOG_TAG, "onEidReady: exception: " + ar.exception);
1158             return;
1159         }
1160 
1161         if (!isValidPhoneIndex(index)) {
1162             Rlog.e(LOG_TAG, "onEidReady: invalid index: " + index);
1163             return;
1164         }
1165         int slotId = mPhoneIdToSlotId[index];
1166         EuiccCard card = (EuiccCard) mUiccSlots[slotId].getUiccCard();
1167         if (card == null) {
1168             Rlog.e(LOG_TAG, "onEidReady: UiccCard in slot " + slotId + " is null");
1169             return;
1170         }
1171 
1172         // set mCardStrings and the defaultEuiccCardId using the now available EID
1173         String eid = card.getEid();
1174         addCardId(eid);
1175         if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
1176                 || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1177             if (!mUiccSlots[slotId].isRemovable()) {
1178                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1179                 logWithLocalLog("onEidReady: eid=" + eid + " slot=" + slotId
1180                         + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1181             } else if (!mHasActiveBuiltInEuicc) {
1182                 // we only set a removable eUICC to the default if there are no active non-removable
1183                 // eUICCs
1184                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1185                 logWithLocalLog("onEidReady: eid=" + eid + " from removable eUICC in slot=" + slotId
1186                         + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1187             }
1188         }
1189         card.unregisterForEidReady(this);
1190     }
1191 
1192     // Return true if the device has at least one built in eUICC based on the resource overlay
hasBuiltInEuicc()1193     private boolean hasBuiltInEuicc() {
1194         return mEuiccSlots != null &&  mEuiccSlots.length > 0;
1195     }
1196 
isBuiltInEuiccSlot(int slotIndex)1197     private boolean isBuiltInEuiccSlot(int slotIndex) {
1198         if (!mHasBuiltInEuicc) {
1199             return false;
1200         }
1201         for (int slot : mEuiccSlots) {
1202             if (slot == slotIndex) {
1203                 return true;
1204             }
1205         }
1206         return false;
1207     }
1208 
1209     /**
1210      * static method to return whether CDMA is supported on the device
1211      * @param context object representative of the application that is calling this method
1212      * @return true if CDMA is supported by the device
1213      */
isCdmaSupported(Context context)1214     public static boolean isCdmaSupported(Context context) {
1215         PackageManager packageManager = context.getPackageManager();
1216         boolean isCdmaSupported =
1217                 packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
1218         return isCdmaSupported;
1219     }
1220 
isValidPhoneIndex(int index)1221     private boolean isValidPhoneIndex(int index) {
1222         return (index >= 0 && index < TelephonyManager.getDefault().getPhoneCount());
1223     }
1224 
isValidSlotIndex(int index)1225     private boolean isValidSlotIndex(int index) {
1226         return (index >= 0 && index < mUiccSlots.length);
1227     }
1228 
1229     @UnsupportedAppUsage
log(String string)1230     private void log(String string) {
1231         Rlog.d(LOG_TAG, string);
1232     }
1233 
logWithLocalLog(String string)1234     private void logWithLocalLog(String string) {
1235         Rlog.d(LOG_TAG, string);
1236         sLocalLog.log("UiccController: " + string);
1237     }
1238 
logeWithLocalLog(String string)1239     private void logeWithLocalLog(String string) {
1240         Rlog.e(LOG_TAG, string);
1241         sLocalLog.log("UiccController: " + string);
1242     }
1243 
1244     /** The supplied log should also indicate the caller to avoid ambiguity. */
addLocalLog(String data)1245     public static void addLocalLog(String data) {
1246         sLocalLog.log(data);
1247     }
1248 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1249     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1250         pw.println("UiccController: " + this);
1251         pw.println(" mContext=" + mContext);
1252         pw.println(" mInstance=" + mInstance);
1253         pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size());
1254         for (int i = 0; i < mIccChangedRegistrants.size(); i++) {
1255             pw.println("  mIccChangedRegistrants[" + i + "]="
1256                     + ((Registrant)mIccChangedRegistrants.get(i)).getHandler());
1257         }
1258         pw.println();
1259         pw.flush();
1260         pw.println(" mIsCdmaSupported=" + isCdmaSupported(mContext));
1261         pw.println(" mHasBuiltInEuicc=" + mHasBuiltInEuicc);
1262         pw.println(" mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc);
1263         pw.println(" mUiccSlots: size=" + mUiccSlots.length);
1264         pw.println(" mCardStrings=" + mCardStrings);
1265         pw.println(" mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1266         for (int i = 0; i < mUiccSlots.length; i++) {
1267             if (mUiccSlots[i] == null) {
1268                 pw.println("  mUiccSlots[" + i + "]=null");
1269             } else {
1270                 pw.println("  mUiccSlots[" + i + "]=" + mUiccSlots[i]);
1271                 mUiccSlots[i].dump(fd, pw, args);
1272             }
1273         }
1274         pw.println(" sLocalLog= ");
1275         sLocalLog.dump(fd, pw, args);
1276     }
1277 }
1278