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             // TODO remove this once modem correctly notifies the unsols
237             // If the device is unencrypted or has been decrypted or FBE is supported,
238             // i.e. not in CryptKeeper bounce, read SIM when radio state is available.
239             // Else wait for radio to be on. This is needed for the scenario when SIM is locked --
240             // to avoid overlap of CryptKeeper and SIM unlock screen.
241             if (!StorageManager.inCryptKeeperBounce()) {
242                 mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
243             } else {
244                 mCis[i].registerForOn(this, EVENT_RADIO_ON, i);
245             }
246             mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
247             mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
248         }
249 
250         mLauncher = new UiccStateChangedLauncher(c, this);
251         mCardStrings = loadCardStrings();
252         mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
253 
254         mEuiccSlots = mContext.getResources()
255                 .getIntArray(com.android.internal.R.array.non_removable_euicc_slots);
256         mHasBuiltInEuicc = hasBuiltInEuicc();
257 
258         PhoneConfigurationManager.registerForMultiSimConfigChange(
259                 this, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
260     }
261 
262     /**
263      * Given the slot index, return the phone ID, or -1 if no phone is associated with the given
264      * slot.
265      * @param slotId the slot index to check
266      * @return the associated phone ID or -1
267      */
getPhoneIdFromSlotId(int slotId)268     public int getPhoneIdFromSlotId(int slotId) {
269         for (int i = 0; i < mPhoneIdToSlotId.length; i++) {
270             if (mPhoneIdToSlotId[i] == slotId) {
271                 return i;
272             }
273         }
274         return -1;
275     }
276 
277     /**
278      * Return the physical slot id associated with the given phoneId, or INVALID_SLOT_ID.
279      * @param phoneId the phoneId to check
280      */
getSlotIdFromPhoneId(int phoneId)281     public int getSlotIdFromPhoneId(int phoneId) {
282         try {
283             return mPhoneIdToSlotId[phoneId];
284         } catch (ArrayIndexOutOfBoundsException e) {
285             return INVALID_SLOT_ID;
286         }
287     }
288 
289     @UnsupportedAppUsage
getInstance()290     public static UiccController getInstance() {
291         synchronized (mLock) {
292             if (mInstance == null) {
293                 throw new RuntimeException(
294                         "UiccController.getInstance can't be called before make()");
295             }
296             return mInstance;
297         }
298     }
299 
300     @UnsupportedAppUsage
getUiccCard(int phoneId)301     public UiccCard getUiccCard(int phoneId) {
302         synchronized (mLock) {
303             return getUiccCardForPhone(phoneId);
304         }
305     }
306 
307     /**
308      * API to get UiccCard corresponding to given physical slot index
309      * @param slotId index of physical slot on the device
310      * @return UiccCard object corresponting to given physical slot index; null if card is
311      * absent
312      */
getUiccCardForSlot(int slotId)313     public UiccCard getUiccCardForSlot(int slotId) {
314         synchronized (mLock) {
315             UiccSlot uiccSlot = getUiccSlot(slotId);
316             if (uiccSlot != null) {
317                 return uiccSlot.getUiccCard();
318             }
319             return null;
320         }
321     }
322 
323     /**
324      * API to get UiccCard corresponding to given phone id
325      * @return UiccCard object corresponding to given phone id; null if there is no card present for
326      * the phone id
327      */
getUiccCardForPhone(int phoneId)328     public UiccCard getUiccCardForPhone(int phoneId) {
329         synchronized (mLock) {
330             if (isValidPhoneIndex(phoneId)) {
331                 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
332                 if (uiccSlot != null) {
333                     return uiccSlot.getUiccCard();
334                 }
335             }
336             return null;
337         }
338     }
339 
340     /**
341      * API to get UiccProfile corresponding to given phone id
342      * @return UiccProfile object corresponding to given phone id; null if there is no card/profile
343      * present for the phone id
344      */
getUiccProfileForPhone(int phoneId)345     public UiccProfile getUiccProfileForPhone(int phoneId) {
346         synchronized (mLock) {
347             if (isValidPhoneIndex(phoneId)) {
348                 UiccCard uiccCard = getUiccCardForPhone(phoneId);
349                 return uiccCard != null ? uiccCard.getUiccProfile() : null;
350             }
351             return null;
352         }
353     }
354 
355     /**
356      * API to get all the UICC slots.
357      * @return UiccSlots array.
358      */
getUiccSlots()359     public UiccSlot[] getUiccSlots() {
360         synchronized (mLock) {
361             return mUiccSlots;
362         }
363     }
364 
365     /** Map logicalSlot to physicalSlot, and activate the physicalSlot if it is inactive. */
switchSlots(int[] physicalSlots, Message response)366     public void switchSlots(int[] physicalSlots, Message response) {
367         logWithLocalLog("switchSlots: " + Arrays.toString(physicalSlots));
368         mRadioConfig.setSimSlotsMapping(physicalSlots, response);
369     }
370 
371     /**
372      * API to get UiccSlot object for a specific physical slot index on the device
373      * @return UiccSlot object for the given physical slot index
374      */
getUiccSlot(int slotId)375     public UiccSlot getUiccSlot(int slotId) {
376         synchronized (mLock) {
377             if (isValidSlotIndex(slotId)) {
378                 return mUiccSlots[slotId];
379             }
380             return null;
381         }
382     }
383 
384     /**
385      * API to get UiccSlot object for a given phone id
386      * @return UiccSlot object for the given phone id
387      */
getUiccSlotForPhone(int phoneId)388     public UiccSlot getUiccSlotForPhone(int phoneId) {
389         synchronized (mLock) {
390             if (isValidPhoneIndex(phoneId)) {
391                 int slotId = getSlotIdFromPhoneId(phoneId);
392                 if (isValidSlotIndex(slotId)) {
393                     return mUiccSlots[slotId];
394                 }
395             }
396             return null;
397         }
398     }
399 
400     /**
401      * API to get UiccSlot object for a given cardId
402      * @param cardId Identifier for a SIM. This can be an ICCID, or an EID in case of an eSIM.
403      * @return int Index of UiccSlot for the given cardId if one is found, {@link #INVALID_SLOT_ID}
404      * otherwise
405      */
getUiccSlotForCardId(String cardId)406     public int getUiccSlotForCardId(String cardId) {
407         synchronized (mLock) {
408             // first look up based on cardId
409             for (int idx = 0; idx < mUiccSlots.length; idx++) {
410                 if (mUiccSlots[idx] != null) {
411                     UiccCard uiccCard = mUiccSlots[idx].getUiccCard();
412                     if (uiccCard != null && cardId.equals(uiccCard.getCardId())) {
413                         return idx;
414                     }
415                 }
416             }
417             // if a match is not found, do a lookup based on ICCID
418             for (int idx = 0; idx < mUiccSlots.length; idx++) {
419                 if (mUiccSlots[idx] != null && cardId.equals(mUiccSlots[idx].getIccId())) {
420                     return idx;
421                 }
422             }
423             return INVALID_SLOT_ID;
424         }
425     }
426 
427     // Easy to use API
428     @UnsupportedAppUsage
getIccRecords(int phoneId, int family)429     public IccRecords getIccRecords(int phoneId, int family) {
430         synchronized (mLock) {
431             UiccCardApplication app = getUiccCardApplication(phoneId, family);
432             if (app != null) {
433                 return app.getIccRecords();
434             }
435             return null;
436         }
437     }
438 
439     // Easy to use API
440     @UnsupportedAppUsage
getIccFileHandler(int phoneId, int family)441     public IccFileHandler getIccFileHandler(int phoneId, int family) {
442         synchronized (mLock) {
443             UiccCardApplication app = getUiccCardApplication(phoneId, family);
444             if (app != null) {
445                 return app.getIccFileHandler();
446             }
447             return null;
448         }
449     }
450 
451 
452     //Notifies when card status changes
453     @UnsupportedAppUsage
registerForIccChanged(Handler h, int what, Object obj)454     public void registerForIccChanged(Handler h, int what, Object obj) {
455         synchronized (mLock) {
456             mIccChangedRegistrants.addUnique(h, what, obj);
457         }
458         //Notify registrant right after registering, so that it will get the latest ICC status,
459         //otherwise which may not happen until there is an actual change in ICC status.
460         Message.obtain(h, what, new AsyncResult(obj, null, null)).sendToTarget();
461     }
462 
unregisterForIccChanged(Handler h)463     public void unregisterForIccChanged(Handler h) {
464         synchronized (mLock) {
465             mIccChangedRegistrants.remove(h);
466         }
467     }
468 
469     @Override
handleMessage(Message msg)470     public void handleMessage (Message msg) {
471         synchronized (mLock) {
472             Integer phoneId = getCiIndex(msg);
473             String eventName = eventToString(msg.what);
474 
475             if (phoneId < 0 || phoneId >= mCis.length) {
476                 Rlog.e(LOG_TAG, "Invalid phoneId : " + phoneId + " received with event "
477                         + eventName);
478                 return;
479             }
480 
481             logWithLocalLog("handleMessage: Received " + eventName + " for phoneId " + phoneId);
482 
483             AsyncResult ar = (AsyncResult)msg.obj;
484             switch (msg.what) {
485                 case EVENT_ICC_STATUS_CHANGED:
486                     if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
487                     mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
488                             phoneId));
489                     break;
490                 case EVENT_RADIO_AVAILABLE:
491                 case EVENT_RADIO_ON:
492                     if (DBG) {
493                         log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "
494                                 + "getIccCardStatus");
495                     }
496                     mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
497                             phoneId));
498                     // slot status should be the same on all RILs; request it only for phoneId 0
499                     if (phoneId == 0) {
500                         if (DBG) {
501                             log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, "
502                                     + "calling getIccSlotsStatus");
503                         }
504                         mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,
505                                 phoneId));
506                     }
507                     break;
508                 case EVENT_GET_ICC_STATUS_DONE:
509                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
510                     onGetIccCardStatusDone(ar, phoneId);
511                     break;
512                 case EVENT_SLOT_STATUS_CHANGED:
513                 case EVENT_GET_SLOT_STATUS_DONE:
514                     if (DBG) {
515                         log("Received EVENT_SLOT_STATUS_CHANGED or EVENT_GET_SLOT_STATUS_DONE");
516                     }
517                     onGetSlotStatusDone(ar);
518                     break;
519                 case EVENT_RADIO_UNAVAILABLE:
520                     if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
521                     UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
522                     if (uiccSlot != null) {
523                         uiccSlot.onRadioStateUnavailable();
524                     }
525                     mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, phoneId, null));
526                     break;
527                 case EVENT_SIM_REFRESH:
528                     if (DBG) log("Received EVENT_SIM_REFRESH");
529                     onSimRefresh(ar, phoneId);
530                     break;
531                 case EVENT_EID_READY:
532                     if (DBG) log("Received EVENT_EID_READY");
533                     onEidReady(ar, phoneId);
534                     break;
535                 case EVENT_MULTI_SIM_CONFIG_CHANGED:
536                     if (DBG) log("Received EVENT_MULTI_SIM_CONFIG_CHANGED");
537                     int activeModemCount = (int) ((AsyncResult) msg.obj).result;
538                     onMultiSimConfigChanged(activeModemCount);
539                     break;
540                 default:
541                     Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
542                     break;
543             }
544         }
545     }
546 
onMultiSimConfigChanged(int newActiveModemCount)547     private void onMultiSimConfigChanged(int newActiveModemCount) {
548         int prevActiveModemCount = mCis.length;
549         mCis = PhoneFactory.getCommandsInterfaces();
550 
551         logWithLocalLog("onMultiSimConfigChanged: prevActiveModemCount " + prevActiveModemCount
552                 + ", newActiveModemCount " + newActiveModemCount);
553 
554         // Resize array.
555         mPhoneIdToSlotId = copyOf(mPhoneIdToSlotId, newActiveModemCount);
556 
557         // Register for new active modem for ss -> ds switch.
558         // For ds -> ss switch, there's no need to unregister as the mCis should unregister
559         // everything itself.
560         for (int i = prevActiveModemCount; i < newActiveModemCount; i++) {
561             mPhoneIdToSlotId[i] = INVALID_SLOT_ID;
562             mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);
563 
564             /*
565              * To support FDE (deprecated), additional check is needed:
566              *
567              * if (!StorageManager.inCryptKeeperBounce()) {
568              *     mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
569              * } else {
570              *     mCis[i].registerForOn(this, EVENT_RADIO_ON, i);
571              * }
572              */
573             mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
574 
575             mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
576             mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
577         }
578     }
579 
getCiIndex(Message msg)580     private Integer getCiIndex(Message msg) {
581         AsyncResult ar;
582         Integer index = new Integer(PhoneConstants.DEFAULT_SLOT_INDEX);
583 
584         /*
585          * The events can be come in two ways. By explicitly sending it using
586          * sendMessage, in this case the user object passed is msg.obj and from
587          * the CommandsInterface, in this case the user object is msg.obj.userObj
588          */
589         if (msg != null) {
590             if (msg.obj != null && msg.obj instanceof Integer) {
591                 index = (Integer)msg.obj;
592             } else if(msg.obj != null && msg.obj instanceof AsyncResult) {
593                 ar = (AsyncResult)msg.obj;
594                 if (ar.userObj != null && ar.userObj instanceof Integer) {
595                     index = (Integer)ar.userObj;
596                 }
597             }
598         }
599         return index;
600     }
601 
eventToString(int event)602     private static String eventToString(int event) {
603         switch (event) {
604             case EVENT_ICC_STATUS_CHANGED: return "ICC_STATUS_CHANGED";
605             case EVENT_SLOT_STATUS_CHANGED: return "SLOT_STATUS_CHANGED";
606             case EVENT_GET_ICC_STATUS_DONE: return "GET_ICC_STATUS_DONE";
607             case EVENT_GET_SLOT_STATUS_DONE: return "GET_SLOT_STATUS_DONE";
608             case EVENT_RADIO_ON: return "RADIO_ON";
609             case EVENT_RADIO_AVAILABLE: return "RADIO_AVAILABLE";
610             case EVENT_RADIO_UNAVAILABLE: return "RADIO_UNAVAILABLE";
611             case EVENT_SIM_REFRESH: return "SIM_REFRESH";
612             case EVENT_EID_READY: return "EID_READY";
613             case EVENT_MULTI_SIM_CONFIG_CHANGED: return "MULTI_SIM_CONFIG_CHANGED";
614             default: return "UNKNOWN(" + event + ")";
615         }
616     }
617 
618     // Easy to use API
619     @UnsupportedAppUsage
getUiccCardApplication(int phoneId, int family)620     public UiccCardApplication getUiccCardApplication(int phoneId, int family) {
621         synchronized (mLock) {
622             UiccCard uiccCard = getUiccCardForPhone(phoneId);
623             if (uiccCard != null) {
624                 return uiccCard.getApplication(family);
625             }
626             return null;
627         }
628     }
629 
getIccStateIntentString(IccCardConstants.State state)630     static String getIccStateIntentString(IccCardConstants.State state) {
631         switch (state) {
632             case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
633             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
634             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
635             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
636             case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
637             case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
638             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
639             case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
640             case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED;
641             case LOADED: return IccCardConstants.INTENT_VALUE_ICC_LOADED;
642             default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
643         }
644     }
645 
updateInternalIccStateForInactiveSlot( Context context, int prevActivePhoneId, String iccId)646     static void updateInternalIccStateForInactiveSlot(
647             Context context, int prevActivePhoneId, String iccId) {
648         if (SubscriptionManager.isValidPhoneId(prevActivePhoneId)) {
649             // Mark SIM state as ABSENT on previously phoneId.
650             TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
651                     Context.TELEPHONY_SERVICE);
652             telephonyManager.setSimStateForPhone(prevActivePhoneId,
653                     IccCardConstants.State.ABSENT.toString());
654         }
655 
656         SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater();
657         if (subInfoUpdator != null) {
658             subInfoUpdator.updateInternalIccStateForInactiveSlot(prevActivePhoneId, iccId);
659         } else {
660             Rlog.e(LOG_TAG, "subInfoUpdate is null.");
661         }
662     }
663 
updateInternalIccState(Context context, IccCardConstants.State state, String reason, int phoneId)664     static void updateInternalIccState(Context context, IccCardConstants.State state, String reason,
665             int phoneId) {
666         TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(
667                 Context.TELEPHONY_SERVICE);
668         telephonyManager.setSimStateForPhone(phoneId, state.toString());
669 
670         SubscriptionInfoUpdater subInfoUpdator = PhoneFactory.getSubscriptionInfoUpdater();
671         if (subInfoUpdator != null) {
672             subInfoUpdator.updateInternalIccState(getIccStateIntentString(state), reason, phoneId);
673         } else {
674             Rlog.e(LOG_TAG, "subInfoUpdate is null.");
675         }
676     }
677 
onGetIccCardStatusDone(AsyncResult ar, Integer index)678     private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
679         if (ar.exception != null) {
680             Rlog.e(LOG_TAG,"Error getting ICC status. "
681                     + "RIL_REQUEST_GET_ICC_STATUS should "
682                     + "never return an error", ar.exception);
683             return;
684         }
685         if (!isValidPhoneIndex(index)) {
686             Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
687             return;
688         }
689 
690         IccCardStatus status = (IccCardStatus)ar.result;
691 
692         logWithLocalLog("onGetIccCardStatusDone: phoneId " + index + " IccCardStatus: " + status);
693 
694         int slotId = status.physicalSlotIndex;
695         if (VDBG) log("onGetIccCardStatusDone: phoneId " + index + " physicalSlotIndex " + slotId);
696         if (slotId == INVALID_SLOT_ID) {
697             slotId = index;
698         }
699 
700         if (eidIsNotSupported(status)) {
701             // we will never get EID from the HAL, so set mDefaultEuiccCardId to UNSUPPORTED_CARD_ID
702             if (DBG) log("eid is not supported");
703             mDefaultEuiccCardId = UNSUPPORTED_CARD_ID;
704         }
705         mPhoneIdToSlotId[index] = slotId;
706 
707         if (VDBG) logPhoneIdToSlotIdMapping();
708 
709         if (mUiccSlots[slotId] == null) {
710             if (VDBG) {
711                 log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = "
712                         + mUiccSlots.length);
713             }
714             mUiccSlots[slotId] = new UiccSlot(mContext, true);
715         }
716 
717         mUiccSlots[slotId].update(mCis[index], status, index, slotId);
718 
719         UiccCard card = mUiccSlots[slotId].getUiccCard();
720         if (card == null) {
721             if (DBG) log("mUiccSlots[" + slotId + "] has no card. Notifying IccChangedRegistrants");
722             mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
723             return;
724         }
725 
726         String cardString = null;
727         boolean isEuicc = mUiccSlots[slotId].isEuicc();
728         if (isEuicc) {
729             cardString = ((EuiccCard) card).getEid();
730         } else {
731             cardString = card.getIccId();
732         }
733 
734         if (cardString != null) {
735             addCardId(cardString);
736         }
737 
738         // EID is unpopulated if Radio HAL < 1.4 (RadioConfig < 1.2)
739         // If so, just register for EID loaded and skip this stuff
740         if (isEuicc && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) {
741             if (cardString == null) {
742                 ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index);
743             } else {
744                 // If we know the EID from IccCardStatus, just use it to set mDefaultEuiccCardId if
745                 // it's not already set.
746                 // This is needed in cases where slot status doesn't include EID, and we don't want
747                 // to register for EID from APDU because we already know cardString from a previous
748                 // APDU
749                 if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
750                         || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
751                     mDefaultEuiccCardId = convertToPublicCardId(cardString);
752                     logWithLocalLog("IccCardStatus eid=" + cardString + " slot=" + slotId
753                             + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
754                 }
755             }
756         }
757 
758         if (DBG) log("Notifying IccChangedRegistrants");
759         mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
760     }
761 
762     /**
763      * Returns true if EID is not supproted.
764      */
eidIsNotSupported(IccCardStatus status)765     private boolean eidIsNotSupported(IccCardStatus status) {
766         // if card status does not contain slot ID, we know we are on HAL < 1.2, so EID will never
767         // be available
768         return status.physicalSlotIndex == INVALID_SLOT_ID;
769     }
770 
771     /**
772      * Add a cardString to mCardStrings. If this is an ICCID, trailing Fs will be automatically
773      * stripped.
774      */
addCardId(String cardString)775     private void addCardId(String cardString) {
776         if (TextUtils.isEmpty(cardString)) {
777             return;
778         }
779         if (cardString.length() < EID_LENGTH) {
780             cardString = IccUtils.stripTrailingFs(cardString);
781         }
782         if (!mCardStrings.contains(cardString)) {
783             mCardStrings.add(cardString);
784             saveCardStrings();
785         }
786     }
787 
788     /**
789      * Converts an integer cardId (public card ID) to a card string.
790      * @param cardId to convert
791      * @return cardString, or null if the cardId is not valid
792      */
convertToCardString(int cardId)793     public String convertToCardString(int cardId) {
794         if (cardId < 0 || cardId >= mCardStrings.size()) {
795             log("convertToCardString: cardId " + cardId + " is not valid");
796             return null;
797         }
798         return mCardStrings.get(cardId);
799     }
800 
801     /**
802      * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId.
803      * If the given cardString is an ICCID, trailing Fs will be automatically stripped before trying
804      * to match to a card ID.
805      *
806      * @return the matching cardId, or UNINITIALIZED_CARD_ID if the card string does not map to a
807      * currently loaded cardId, or UNSUPPORTED_CARD_ID if the device does not support card IDs
808      */
convertToPublicCardId(String cardString)809     public int convertToPublicCardId(String cardString) {
810         if (mDefaultEuiccCardId == UNSUPPORTED_CARD_ID) {
811             // even if cardString is not an EID, if EID is not supported (e.g. HAL < 1.2) we can't
812             // guarentee a working card ID implementation, so return UNSUPPORTED_CARD_ID
813             return UNSUPPORTED_CARD_ID;
814         }
815         if (TextUtils.isEmpty(cardString)) {
816             return UNINITIALIZED_CARD_ID;
817         }
818 
819         if (cardString.length() < EID_LENGTH) {
820             cardString = IccUtils.stripTrailingFs(cardString);
821         }
822         int id = mCardStrings.indexOf(cardString);
823         if (id == -1) {
824             return UNINITIALIZED_CARD_ID;
825         } else {
826             return id;
827         }
828     }
829 
830     /**
831      * Returns the UiccCardInfo of all currently inserted UICCs and embedded eUICCs.
832      */
getAllUiccCardInfos()833     public ArrayList<UiccCardInfo> getAllUiccCardInfos() {
834         ArrayList<UiccCardInfo> infos = new ArrayList<>();
835         for (int slotIndex = 0; slotIndex < mUiccSlots.length; slotIndex++) {
836             final UiccSlot slot = mUiccSlots[slotIndex];
837             if (slot == null) continue;
838             boolean isEuicc = slot.isEuicc();
839             String eid = null;
840             UiccCard card = slot.getUiccCard();
841             String iccid = null;
842             int cardId = UNINITIALIZED_CARD_ID;
843             boolean isRemovable = slot.isRemovable();
844 
845             // first we try to populate UiccCardInfo using the UiccCard, but if it doesn't exist
846             // (e.g. the slot is for an inactive eUICC) then we try using the UiccSlot.
847             if (card != null) {
848                 iccid = card.getIccId();
849                 if (isEuicc) {
850                     eid = ((EuiccCard) card).getEid();
851                     cardId = convertToPublicCardId(eid);
852                 } else {
853                     // leave eid null if the UICC is not embedded
854                     cardId = convertToPublicCardId(iccid);
855                 }
856             } else {
857                 iccid = slot.getIccId();
858                 // Fill in the fields we can
859                 if (!isEuicc && !TextUtils.isEmpty(iccid)) {
860                     cardId = convertToPublicCardId(iccid);
861                 }
862             }
863             UiccCardInfo info = new UiccCardInfo(isEuicc, cardId, eid,
864                     IccUtils.stripTrailingFs(iccid), slotIndex, isRemovable);
865             infos.add(info);
866         }
867         return infos;
868     }
869 
870     /**
871      * Get the card ID of the default eUICC.
872      */
getCardIdForDefaultEuicc()873     public int getCardIdForDefaultEuicc() {
874         if (mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
875             return UNSUPPORTED_CARD_ID;
876         }
877         return mDefaultEuiccCardId;
878     }
879 
loadCardStrings()880     private ArrayList<String> loadCardStrings() {
881         String cardStrings =
882                 PreferenceManager.getDefaultSharedPreferences(mContext).getString(CARD_STRINGS, "");
883         if (TextUtils.isEmpty(cardStrings)) {
884             // just return an empty list, since String.split would return the list { "" }
885             return new ArrayList<String>();
886         }
887         return new ArrayList<String>(Arrays.asList(cardStrings.split(",")));
888     }
889 
saveCardStrings()890     private void saveCardStrings() {
891         SharedPreferences.Editor editor =
892                 PreferenceManager.getDefaultSharedPreferences(mContext).edit();
893         editor.putString(CARD_STRINGS, TextUtils.join(",", mCardStrings));
894         editor.commit();
895     }
896 
onGetSlotStatusDone(AsyncResult ar)897     private synchronized void onGetSlotStatusDone(AsyncResult ar) {
898         if (!mIsSlotStatusSupported) {
899             if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false");
900             return;
901         }
902         Throwable e = ar.exception;
903         if (e != null) {
904             if (!(e instanceof CommandException) || ((CommandException) e).getCommandError()
905                     != CommandException.Error.REQUEST_NOT_SUPPORTED) {
906                 // this is not expected; there should be no exception other than
907                 // REQUEST_NOT_SUPPORTED
908                 logeWithLocalLog("Unexpected error getting slot status: " + ar.exception);
909             } else {
910                 // REQUEST_NOT_SUPPORTED
911                 logWithLocalLog("onGetSlotStatusDone: request not supported; marking "
912                         + "mIsSlotStatusSupported to false");
913                 mIsSlotStatusSupported = false;
914             }
915             return;
916         }
917 
918         ArrayList<IccSlotStatus> status = (ArrayList<IccSlotStatus>) ar.result;
919 
920         if (!slotStatusChanged(status)) {
921             log("onGetSlotStatusDone: No change in slot status");
922             return;
923         }
924         logWithLocalLog("onGetSlotStatusDone: " + status);
925 
926         sLastSlotStatus = status;
927 
928         int numActiveSlots = 0;
929         boolean isDefaultEuiccCardIdSet = false;
930         boolean anyEuiccIsActive = false;
931         mHasActiveBuiltInEuicc = false;
932 
933         int numSlots = status.size();
934         if (mUiccSlots.length < numSlots) {
935             logeWithLocalLog("The number of the physical slots reported " + numSlots
936                     + " is greater than the expectation " + mUiccSlots.length);
937             numSlots = mUiccSlots.length;
938         }
939 
940         for (int i = 0; i < numSlots; i++) {
941             IccSlotStatus iss = status.get(i);
942             boolean isActive = (iss.slotState == IccSlotStatus.SlotState.SLOTSTATE_ACTIVE);
943             if (isActive) {
944                 numActiveSlots++;
945 
946                 // Correctness check: logicalSlotIndex should be valid for an active slot
947                 if (!isValidPhoneIndex(iss.logicalSlotIndex)) {
948                     Rlog.e(LOG_TAG, "Skipping slot " + i + " as phone " + iss.logicalSlotIndex
949                                + " is not available to communicate with this slot");
950                 } else {
951                     mPhoneIdToSlotId[iss.logicalSlotIndex] = i;
952                 }
953             }
954 
955             if (mUiccSlots[i] == null) {
956                 if (VDBG) {
957                     log("Creating mUiccSlot[" + i + "]; mUiccSlots.length = " + mUiccSlots.length);
958                 }
959                 mUiccSlots[i] = new UiccSlot(mContext, isActive);
960             }
961 
962             if (!isValidPhoneIndex(iss.logicalSlotIndex)) {
963                 mUiccSlots[i].update(null, iss, i /* slotIndex */);
964             } else {
965                 mUiccSlots[i].update(isActive ? mCis[iss.logicalSlotIndex] : null, iss,
966                         i /* slotIndex */);
967             }
968 
969             if (mUiccSlots[i].isEuicc()) {
970                 if (isActive) {
971                     anyEuiccIsActive = true;
972 
973                     if (isBuiltInEuiccSlot(i)) {
974                         mHasActiveBuiltInEuicc = true;
975                     }
976                 }
977                 String eid = iss.eid;
978                 if (TextUtils.isEmpty(eid)) {
979                     // iss.eid is not populated on HAL<1.4
980                     continue;
981                 }
982 
983                 addCardId(eid);
984 
985                 // whenever slot status is received, set default card to the non-removable eUICC
986                 // with the lowest slot index.
987                 if (!mUiccSlots[i].isRemovable() && !isDefaultEuiccCardIdSet) {
988                     isDefaultEuiccCardIdSet = true;
989                     mDefaultEuiccCardId = convertToPublicCardId(eid);
990                     logWithLocalLog("Using eid=" + eid + " in slot=" + i
991                             + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId);
992                 }
993             }
994         }
995 
996         if (!mHasActiveBuiltInEuicc && !isDefaultEuiccCardIdSet) {
997             // if there are no active built-in eUICCs, then consider setting a removable eUICC to
998             // the default.
999             // Note that on HAL<1.2, it's possible that a built-in eUICC exists, but does not
1000             // correspond to any slot in mUiccSlots. This logic is still safe in that case because
1001             // SlotStatus is only for HAL >= 1.2
1002             for (int i = 0; i < numSlots; i++) {
1003                 if (mUiccSlots[i].isEuicc()) {
1004                     String eid = status.get(i).eid;
1005                     if (!TextUtils.isEmpty(eid)) {
1006                         isDefaultEuiccCardIdSet = true;
1007                         mDefaultEuiccCardId = convertToPublicCardId(eid);
1008                         logWithLocalLog("Using eid=" + eid + " from removable eUICC in slot="
1009                                 + i + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1010                         break;
1011                     }
1012                 }
1013             }
1014         }
1015 
1016         if (mHasBuiltInEuicc && !anyEuiccIsActive && !isDefaultEuiccCardIdSet) {
1017             logWithLocalLog(
1018                     "onGetSlotStatusDone: mDefaultEuiccCardId=TEMPORARILY_UNSUPPORTED_CARD_ID");
1019             isDefaultEuiccCardIdSet = true;
1020             mDefaultEuiccCardId = TEMPORARILY_UNSUPPORTED_CARD_ID;
1021         }
1022 
1023 
1024         if (!isDefaultEuiccCardIdSet) {
1025             if (mDefaultEuiccCardId >= 0) {
1026                 // if mDefaultEuiccCardId has already been set to an actual eUICC,
1027                 // don't overwrite mDefaultEuiccCardId unless that eUICC is no longer inserted
1028                 boolean defaultEuiccCardIdIsStillInserted = false;
1029                 String cardString = mCardStrings.get(mDefaultEuiccCardId);
1030                 for (UiccSlot slot : mUiccSlots) {
1031                     if (slot.getUiccCard() == null) {
1032                         continue;
1033                     }
1034                     if (cardString.equals(
1035                             IccUtils.stripTrailingFs(slot.getUiccCard().getCardId()))) {
1036                         defaultEuiccCardIdIsStillInserted = true;
1037                     }
1038                 }
1039                 if (!defaultEuiccCardIdIsStillInserted) {
1040                     logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId="
1041                             + mDefaultEuiccCardId
1042                             + " is no longer inserted. Setting mDefaultEuiccCardId=UNINITIALIZED");
1043                     mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1044                 }
1045             } else {
1046                 // no known eUICCs at all (it's possible that an eUICC is inserted and we just don't
1047                 // know it's EID)
1048                 logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId=UNINITIALIZED");
1049                 mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1050             }
1051         }
1052 
1053         if (VDBG) logPhoneIdToSlotIdMapping();
1054 
1055         // Correctness check: number of active slots should be valid
1056         if (numActiveSlots != mPhoneIdToSlotId.length) {
1057             Rlog.e(LOG_TAG, "Number of active slots " + numActiveSlots
1058                        + " does not match the number of Phones" + mPhoneIdToSlotId.length);
1059         }
1060 
1061         // Correctness check: slotIds should be unique in mPhoneIdToSlotId
1062         Set<Integer> slotIds = new HashSet<>();
1063         for (int slotId : mPhoneIdToSlotId) {
1064             if (slotIds.contains(slotId)) {
1065                 throw new RuntimeException("slotId " + slotId + " mapped to multiple phoneIds");
1066             }
1067             slotIds.add(slotId);
1068         }
1069 
1070         // broadcast slot status changed
1071         final BroadcastOptions options = BroadcastOptions.makeBasic();
1072         options.setBackgroundActivityStartsAllowed(true);
1073         Intent intent = new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED);
1074         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1075         mContext.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1076                 options.toBundle());
1077     }
1078 
slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList)1079     private boolean slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList) {
1080         if (sLastSlotStatus == null || sLastSlotStatus.size() != slotStatusList.size()) {
1081             return true;
1082         }
1083         for (IccSlotStatus iccSlotStatus : slotStatusList) {
1084             if (!sLastSlotStatus.contains(iccSlotStatus)) {
1085                 return true;
1086             }
1087         }
1088         return false;
1089     }
1090 
logPhoneIdToSlotIdMapping()1091     private void logPhoneIdToSlotIdMapping() {
1092         log("mPhoneIdToSlotId mapping:");
1093         for (int i = 0; i < mPhoneIdToSlotId.length; i++) {
1094             log("    phoneId " + i + " slotId " + mPhoneIdToSlotId[i]);
1095         }
1096     }
1097 
onSimRefresh(AsyncResult ar, Integer index)1098     private void onSimRefresh(AsyncResult ar, Integer index) {
1099         if (ar.exception != null) {
1100             Rlog.e(LOG_TAG, "onSimRefresh: Sim REFRESH with exception: " + ar.exception);
1101             return;
1102         }
1103 
1104         if (!isValidPhoneIndex(index)) {
1105             Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index);
1106             return;
1107         }
1108 
1109         IccRefreshResponse resp = (IccRefreshResponse) ar.result;
1110         logWithLocalLog("onSimRefresh: index " + index + ", " + resp);
1111 
1112         if (resp == null) {
1113             Rlog.e(LOG_TAG, "onSimRefresh: received without input");
1114             return;
1115         }
1116 
1117         UiccCard uiccCard = getUiccCardForPhone(index);
1118         if (uiccCard == null) {
1119             Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index);
1120             return;
1121         }
1122 
1123         boolean changed = false;
1124         switch(resp.refreshResult) {
1125             // Reset the required apps when we know about the refresh so that
1126             // anyone interested does not get stale state.
1127             case IccRefreshResponse.REFRESH_RESULT_RESET:
1128                 changed = uiccCard.resetAppWithAid(resp.aid, true /* reset */);
1129                 break;
1130             case IccRefreshResponse.REFRESH_RESULT_INIT:
1131                 // don't dispose CatService on SIM REFRESH of type INIT
1132                 changed = uiccCard.resetAppWithAid(resp.aid, false /* initialize */);
1133                 break;
1134             default:
1135                 return;
1136         }
1137 
1138         if (changed && resp.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
1139             // If there is any change on RESET, reset carrier config as well. From carrier config
1140             // perspective, this is treated the same as sim state unknown
1141             CarrierConfigManager configManager = (CarrierConfigManager)
1142                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1143             configManager.updateConfigForPhoneId(index, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
1144 
1145             boolean requirePowerOffOnSimRefreshReset = mContext.getResources().getBoolean(
1146                     com.android.internal.R.bool.config_requireRadioPowerOffOnSimRefreshReset);
1147             if (requirePowerOffOnSimRefreshReset) {
1148                 mCis[index].setRadioPower(false, null);
1149             }
1150         }
1151 
1152         // The card status could have changed. Get the latest state.
1153         mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
1154     }
1155 
1156     // for HAL 1.2-1.3 we register for EID ready, set mCardStrings and mDefaultEuiccCardId here.
1157     // Note that if there are multiple eUICCs on HAL 1.2-1.3, the default eUICC is the one whose EID
1158     // is first loaded
onEidReady(AsyncResult ar, Integer index)1159     private void onEidReady(AsyncResult ar, Integer index) {
1160         if (ar.exception != null) {
1161             Rlog.e(LOG_TAG, "onEidReady: exception: " + ar.exception);
1162             return;
1163         }
1164 
1165         if (!isValidPhoneIndex(index)) {
1166             Rlog.e(LOG_TAG, "onEidReady: invalid index: " + index);
1167             return;
1168         }
1169         int slotId = mPhoneIdToSlotId[index];
1170         EuiccCard card = (EuiccCard) mUiccSlots[slotId].getUiccCard();
1171         if (card == null) {
1172             Rlog.e(LOG_TAG, "onEidReady: UiccCard in slot " + slotId + " is null");
1173             return;
1174         }
1175 
1176         // set mCardStrings and the defaultEuiccCardId using the now available EID
1177         String eid = card.getEid();
1178         addCardId(eid);
1179         if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
1180                 || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1181             if (!mUiccSlots[slotId].isRemovable()) {
1182                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1183                 logWithLocalLog("onEidReady: eid=" + eid + " slot=" + slotId
1184                         + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1185             } else if (!mHasActiveBuiltInEuicc) {
1186                 // we only set a removable eUICC to the default if there are no active non-removable
1187                 // eUICCs
1188                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1189                 logWithLocalLog("onEidReady: eid=" + eid + " from removable eUICC in slot=" + slotId
1190                         + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1191             }
1192         }
1193         card.unregisterForEidReady(this);
1194     }
1195 
1196     // Return true if the device has at least one built in eUICC based on the resource overlay
hasBuiltInEuicc()1197     private boolean hasBuiltInEuicc() {
1198         return mEuiccSlots != null &&  mEuiccSlots.length > 0;
1199     }
1200 
isBuiltInEuiccSlot(int slotIndex)1201     private boolean isBuiltInEuiccSlot(int slotIndex) {
1202         if (!mHasBuiltInEuicc) {
1203             return false;
1204         }
1205         for (int slot : mEuiccSlots) {
1206             if (slot == slotIndex) {
1207                 return true;
1208             }
1209         }
1210         return false;
1211     }
1212 
1213     /**
1214      * static method to return whether CDMA is supported on the device
1215      * @param context object representative of the application that is calling this method
1216      * @return true if CDMA is supported by the device
1217      */
isCdmaSupported(Context context)1218     public static boolean isCdmaSupported(Context context) {
1219         PackageManager packageManager = context.getPackageManager();
1220         boolean isCdmaSupported =
1221                 packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
1222         return isCdmaSupported;
1223     }
1224 
isValidPhoneIndex(int index)1225     private boolean isValidPhoneIndex(int index) {
1226         return (index >= 0 && index < TelephonyManager.getDefault().getPhoneCount());
1227     }
1228 
isValidSlotIndex(int index)1229     private boolean isValidSlotIndex(int index) {
1230         return (index >= 0 && index < mUiccSlots.length);
1231     }
1232 
1233     @UnsupportedAppUsage
log(String string)1234     private void log(String string) {
1235         Rlog.d(LOG_TAG, string);
1236     }
1237 
logWithLocalLog(String string)1238     private void logWithLocalLog(String string) {
1239         Rlog.d(LOG_TAG, string);
1240         sLocalLog.log("UiccController: " + string);
1241     }
1242 
logeWithLocalLog(String string)1243     private void logeWithLocalLog(String string) {
1244         Rlog.e(LOG_TAG, string);
1245         sLocalLog.log("UiccController: " + string);
1246     }
1247 
1248     /** The supplied log should also indicate the caller to avoid ambiguity. */
addLocalLog(String data)1249     public static void addLocalLog(String data) {
1250         sLocalLog.log(data);
1251     }
1252 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1253     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1254         pw.println("UiccController: " + this);
1255         pw.println(" mContext=" + mContext);
1256         pw.println(" mInstance=" + mInstance);
1257         pw.println(" mIccChangedRegistrants: size=" + mIccChangedRegistrants.size());
1258         for (int i = 0; i < mIccChangedRegistrants.size(); i++) {
1259             pw.println("  mIccChangedRegistrants[" + i + "]="
1260                     + ((Registrant)mIccChangedRegistrants.get(i)).getHandler());
1261         }
1262         pw.println();
1263         pw.flush();
1264         pw.println(" mIsCdmaSupported=" + isCdmaSupported(mContext));
1265         pw.println(" mHasBuiltInEuicc=" + mHasBuiltInEuicc);
1266         pw.println(" mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc);
1267         pw.println(" mUiccSlots: size=" + mUiccSlots.length);
1268         pw.println(" mCardStrings=" + mCardStrings);
1269         pw.println(" mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1270         for (int i = 0; i < mUiccSlots.length; i++) {
1271             if (mUiccSlots[i] == null) {
1272                 pw.println("  mUiccSlots[" + i + "]=null");
1273             } else {
1274                 pw.println("  mUiccSlots[" + i + "]=" + mUiccSlots[i]);
1275                 mUiccSlots[i].dump(fd, pw, args);
1276             }
1277         }
1278         pw.println(" sLocalLog= ");
1279         sLocalLog.dump(fd, pw, args);
1280     }
1281 }
1282