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