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.Manifest;
25 import android.annotation.NonNull;
26 import android.annotation.Nullable;
27 import android.app.BroadcastOptions;
28 import android.compat.annotation.UnsupportedAppUsage;
29 import android.content.Context;
30 import android.content.Intent;
31 import android.content.SharedPreferences;
32 import android.content.pm.PackageManager;
33 import android.os.AsyncResult;
34 import android.os.Build;
35 import android.os.Handler;
36 import android.os.Message;
37 import android.os.RegistrantList;
38 import android.preference.PreferenceManager;
39 import android.sysprop.TelephonyProperties;
40 import android.telephony.AnomalyReporter;
41 import android.telephony.CarrierConfigManager;
42 import android.telephony.SubscriptionInfo;
43 import android.telephony.SubscriptionManager;
44 import android.telephony.TelephonyManager;
45 import android.telephony.TelephonyManager.SimState;
46 import android.telephony.UiccCardInfo;
47 import android.telephony.UiccPortInfo;
48 import android.telephony.UiccSlotMapping;
49 import android.telephony.data.ApnSetting;
50 import android.text.TextUtils;
51 import android.util.IndentingPrintWriter;
52 import android.util.LocalLog;
53 import android.util.Log;
54 
55 import com.android.internal.annotations.VisibleForTesting;
56 import com.android.internal.telephony.CarrierServiceBindHelper;
57 import com.android.internal.telephony.CommandException;
58 import com.android.internal.telephony.CommandsInterface;
59 import com.android.internal.telephony.IccCard;
60 import com.android.internal.telephony.IccCardConstants;
61 import com.android.internal.telephony.IntentBroadcaster;
62 import com.android.internal.telephony.PhoneConfigurationManager;
63 import com.android.internal.telephony.PhoneConstants;
64 import com.android.internal.telephony.PhoneFactory;
65 import com.android.internal.telephony.RadioConfig;
66 import com.android.internal.telephony.TelephonyIntents;
67 import com.android.internal.telephony.metrics.TelephonyMetrics;
68 import com.android.internal.telephony.subscription.SubscriptionManagerService;
69 import com.android.internal.telephony.uicc.euicc.EuiccCard;
70 import com.android.internal.telephony.util.ArrayUtils;
71 import com.android.internal.telephony.util.TelephonyUtils;
72 import com.android.telephony.Rlog;
73 
74 import java.io.FileDescriptor;
75 import java.io.PrintWriter;
76 import java.util.ArrayList;
77 import java.util.Arrays;
78 import java.util.List;
79 import java.util.UUID;
80 import java.util.stream.Collectors;
81 import java.util.stream.IntStream;
82 
83 /**
84  * This class is responsible for keeping all knowledge about
85  * Universal Integrated Circuit Card (UICC), also know as SIM's,
86  * in the system. It is also used as API to get appropriate
87  * applications to pass them to phone and service trackers.
88  *
89  * UiccController is created with the call to make() function.
90  * UiccController is a singleton and make() must only be called once
91  * and throws an exception if called multiple times.
92  *
93  * Once created UiccController registers with RIL for "on" and "unsol_sim_status_changed"
94  * notifications. When such notification arrives UiccController will call
95  * getIccCardStatus (GET_SIM_STATUS). Based on the response of GET_SIM_STATUS
96  * request appropriate tree of uicc objects will be created.
97  *
98  * Following is class diagram for uicc classes:
99  *
100  *                       UiccController
101  *                            #
102  *                            |
103  *                        UiccSlot[]
104  *                            #
105  *                            |
106  *                        UiccCard
107  *                            #
108  *                            |
109  *                        UiccPort[]
110  *                            #
111  *                            |
112  *                       UiccProfile
113  *                          #   #
114  *                          |   ------------------
115  *                    UiccCardApplication    CatService
116  *                      #            #
117  *                      |            |
118  *                 IccRecords    IccFileHandler
119  *                 ^ ^ ^           ^ ^ ^ ^ ^
120  *    SIMRecords---- | |           | | | | ---SIMFileHandler
121  *    RuimRecords----- |           | | | ----RuimFileHandler
122  *    IsimUiccRecords---           | | -----UsimFileHandler
123  *                                 | ------CsimFileHandler
124  *                                 ----IsimFileHandler
125  *
126  * Legend: # stands for Composition
127  *         ^ stands for Generalization
128  *
129  * See also {@link com.android.internal.telephony.IccCard}
130  */
131 public class UiccController extends Handler {
132     private static final boolean DBG = true;
133     private static final boolean VDBG = false; //STOPSHIP if true
134     private static final String LOG_TAG = "UiccController";
135 
136     public static final int INVALID_SLOT_ID = -1;
137 
138     public static final int APP_FAM_3GPP =  1;
139     public static final int APP_FAM_3GPP2 = 2;
140     public static final int APP_FAM_IMS   = 3;
141 
142     private static final int EVENT_ICC_STATUS_CHANGED = 1;
143     private static final int EVENT_SLOT_STATUS_CHANGED = 2;
144     private static final int EVENT_GET_ICC_STATUS_DONE = 3;
145     private static final int EVENT_GET_SLOT_STATUS_DONE = 4;
146     private static final int EVENT_RADIO_ON = 5;
147     private static final int EVENT_RADIO_AVAILABLE = 6;
148     private static final int EVENT_RADIO_UNAVAILABLE = 7;
149     private static final int EVENT_SIM_REFRESH = 8;
150     private static final int EVENT_EID_READY = 9;
151     private static final int EVENT_MULTI_SIM_CONFIG_CHANGED = 10;
152     // NOTE: any new EVENT_* values must be added to eventToString.
153 
154     @NonNull
155     private final TelephonyManager mTelephonyManager;
156 
157     // this needs to be here, because on bootup we dont know which index maps to which UiccSlot
158     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
159     private CommandsInterface[] mCis;
160     @VisibleForTesting
161     public UiccSlot[] mUiccSlots;
162     private int[] mPhoneIdToSlotId;
163     private boolean mIsSlotStatusSupported = true;
164 
165     // This maps the externally exposed card ID (int) to the internal card ID string (ICCID/EID).
166     // The array index is the card ID (int).
167     // This mapping exists to expose card-based functionality without exposing the EID, which is
168     // considered sensitive information.
169     // mCardStrings is populated using values from the IccSlotStatus and IccCardStatus. For
170     // HAL < 1.2, these do not contain the EID or the ICCID, so mCardStrings will be empty
171     private ArrayList<String> mCardStrings;
172 
173     /**
174      * SIM card state.
175      */
176     @NonNull
177     @SimState
178     private final int[] mSimCardState;
179 
180     /**
181      * SIM application state.
182      */
183     @NonNull
184     @SimState
185     private final int[] mSimApplicationState;
186 
187     // This is the card ID of the default eUICC. It starts as UNINITIALIZED_CARD_ID.
188     // When we load the EID (either with slot status or from the EuiccCard), we set it to the eUICC
189     // with the lowest slot index.
190     // If EID is not supported (e.g. on HAL version < 1.2), we set it to UNSUPPORTED_CARD_ID
191     private int mDefaultEuiccCardId;
192 
193     // Default Euicc Card ID used when the device is temporarily unable to read the EID (e.g. on HAL
194     // 1.2-1.3 if the eUICC is currently inactive). This value is only used within the
195     // UiccController and should be converted to UNSUPPORTED_CARD_ID when others ask.
196     // (This value is -3 because UNSUPPORTED_CARD_ID and UNINITIALIZED_CARD_ID are -1 and -2)
197     private static final int TEMPORARILY_UNSUPPORTED_CARD_ID = -3;
198 
199     // GSM SGP.02 section 2.2.2 states that the EID is always 32 digits long
200     private static final int EID_LENGTH = 32;
201 
202     // SharedPreference key for saving the known card strings (ICCIDs and EIDs) ordered by card ID
203     private static final String CARD_STRINGS = "card_strings";
204 
205     // SharedPreference key for saving the flag to set removable eSIM as default eUICC or not.
206     private static final String REMOVABLE_ESIM_AS_DEFAULT = "removable_esim";
207 
208     // Whether the device has an eUICC built in.
209     private boolean mHasBuiltInEuicc = false;
210 
211     // Whether the device has a currently active built in eUICC
212     private boolean mHasActiveBuiltInEuicc = false;
213 
214     // Use removable eSIM as default eUICC. This flag will be set from phone debug hidden menu
215     private boolean mUseRemovableEsimAsDefault = false;
216 
217     // The physical slots which correspond to built-in eUICCs
218     private final int[] mEuiccSlots;
219 
220     // SharedPreferences key for saving the default euicc card ID
221     private static final String DEFAULT_CARD = "default_card";
222 
223     @UnsupportedAppUsage
224     private static final Object mLock = new Object();
225     @UnsupportedAppUsage
226     private static UiccController mInstance;
227     @VisibleForTesting
228     public static ArrayList<IccSlotStatus> sLastSlotStatus;
229 
230     @UnsupportedAppUsage
231     @VisibleForTesting
232     public Context mContext;
233 
234     protected RegistrantList mIccChangedRegistrants = new RegistrantList();
235 
236     @NonNull
237     private final CarrierServiceBindHelper mCarrierServiceBindHelper;
238 
239     private UiccStateChangedLauncher mLauncher;
240     private RadioConfig mRadioConfig;
241 
242     /* The storage for the PIN codes. */
243     private final PinStorage mPinStorage;
244 
245     // LocalLog buffer to hold important SIM related events for debugging
246     private static LocalLog sLocalLog = new LocalLog(TelephonyUtils.IS_DEBUGGABLE ? 256 : 64);
247 
248     /**
249      * API to make UiccController singleton if not already created.
250      */
make(Context c)251     public static UiccController make(Context c) {
252         synchronized (mLock) {
253             if (mInstance != null) {
254                 throw new RuntimeException("UiccController.make() should only be called once");
255             }
256             mInstance = new UiccController(c);
257             return mInstance;
258         }
259     }
260 
UiccController(Context c)261     private UiccController(Context c) {
262         if (DBG) log("Creating UiccController");
263         mContext = c;
264         mCis = PhoneFactory.getCommandsInterfaces();
265         int numPhysicalSlots = c.getResources().getInteger(
266                 com.android.internal.R.integer.config_num_physical_slots);
267         numPhysicalSlots = TelephonyProperties.sim_slots_count().orElse(numPhysicalSlots);
268         if (DBG) {
269             logWithLocalLog("config_num_physical_slots = " + numPhysicalSlots);
270         }
271         // Minimum number of physical slot count should be equals to or greater than phone count,
272         // if it is less than phone count use phone count as physical slot count.
273         if (numPhysicalSlots < mCis.length) {
274             numPhysicalSlots = mCis.length;
275         }
276 
277         mTelephonyManager = mContext.getSystemService(TelephonyManager.class);
278 
279         mUiccSlots = new UiccSlot[numPhysicalSlots];
280         mPhoneIdToSlotId = new int[mCis.length];
281         int supportedModemCount = mTelephonyManager.getSupportedModemCount();
282         mSimCardState = new int[supportedModemCount];
283         mSimApplicationState = new int[supportedModemCount];
284         Arrays.fill(mPhoneIdToSlotId, INVALID_SLOT_ID);
285         if (VDBG) logPhoneIdToSlotIdMapping();
286         mRadioConfig = RadioConfig.getInstance();
287         mRadioConfig.registerForSimSlotStatusChanged(this, EVENT_SLOT_STATUS_CHANGED, null);
288         for (int i = 0; i < mCis.length; i++) {
289             mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);
290             mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
291             mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
292             mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
293         }
294 
295         mLauncher = new UiccStateChangedLauncher(c, this);
296         mCardStrings = loadCardStrings();
297         mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
298 
299         mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
300 
301         mEuiccSlots = mContext.getResources()
302                 .getIntArray(com.android.internal.R.array.non_removable_euicc_slots);
303         mHasBuiltInEuicc = hasBuiltInEuicc();
304 
305         PhoneConfigurationManager.registerForMultiSimConfigChange(
306                 this, EVENT_MULTI_SIM_CONFIG_CHANGED, null);
307 
308         mPinStorage = new PinStorage(mContext);
309         if (!TelephonyUtils.IS_USER) {
310             mUseRemovableEsimAsDefault = PreferenceManager.getDefaultSharedPreferences(mContext)
311                     .getBoolean(REMOVABLE_ESIM_AS_DEFAULT, false);
312         }
313     }
314 
315     /**
316      * Given the slot index and port index, return the phone ID, or -1 if no phone is associated
317      * with the given slot and port.
318      * @param slotId the slot index to check
319      * @param portIndex unique index referring to a port belonging to the SIM slot
320      * @return the associated phone ID or -1
321      */
getPhoneIdFromSlotPortIndex(int slotId, int portIndex)322     public int getPhoneIdFromSlotPortIndex(int slotId, int portIndex) {
323         UiccSlot slot = getUiccSlot(slotId);
324         return slot == null ? UiccSlot.INVALID_PHONE_ID : slot.getPhoneIdFromPortIndex(portIndex);
325     }
326 
327     /**
328      * Return the physical slot id associated with the given phoneId, or INVALID_SLOT_ID.
329      * @param phoneId the phoneId to check
330      */
getSlotIdFromPhoneId(int phoneId)331     public int getSlotIdFromPhoneId(int phoneId) {
332         try {
333             return mPhoneIdToSlotId[phoneId];
334         } catch (ArrayIndexOutOfBoundsException e) {
335             return INVALID_SLOT_ID;
336         }
337     }
338 
339     @UnsupportedAppUsage
getInstance()340     public static UiccController getInstance() {
341         if (mInstance == null) {
342             throw new RuntimeException(
343                     "UiccController.getInstance can't be called before make()");
344         }
345         return mInstance;
346     }
347 
348     @UnsupportedAppUsage
getUiccCard(int phoneId)349     public UiccCard getUiccCard(int phoneId) {
350         synchronized (mLock) {
351             return getUiccCardForPhone(phoneId);
352         }
353     }
354 
355     /**
356      * Return the UiccPort associated with the given phoneId or null if no phoneId is associated.
357      * @param phoneId the phoneId to check
358      */
getUiccPort(int phoneId)359     public UiccPort getUiccPort(int phoneId) {
360         synchronized (mLock) {
361             return getUiccPortForPhone(phoneId);
362         }
363     }
364 
365     /**
366      * API to get UiccPort corresponding to given physical slot index and port index
367      * @param slotId index of physical slot on the device
368      * @param portIdx index of port on the card
369      * @return UiccPort object corresponding to given physical slot index and port index;
370      * null if port does not exist.
371      */
getUiccPortForSlot(int slotId, int portIdx)372     public UiccPort getUiccPortForSlot(int slotId, int portIdx) {
373         synchronized (mLock) {
374             UiccSlot slot = getUiccSlot(slotId);
375             if (slot != null) {
376                 UiccCard uiccCard = slot.getUiccCard();
377                 if (uiccCard != null) {
378                     return uiccCard.getUiccPort(portIdx);
379                 }
380             }
381             return null;
382         }
383     }
384 
385     /**
386      * API to get UiccCard corresponding to given physical slot index
387      * @param slotId index of physical slot on the device
388      * @return UiccCard object corresponting to given physical slot index; null if card is
389      * absent
390      */
getUiccCardForSlot(int slotId)391     public UiccCard getUiccCardForSlot(int slotId) {
392         synchronized (mLock) {
393             UiccSlot uiccSlot = getUiccSlot(slotId);
394             if (uiccSlot != null) {
395                 return uiccSlot.getUiccCard();
396             }
397             return null;
398         }
399     }
400 
401     /**
402      * API to get UiccCard corresponding to given phone id
403      * @return UiccCard object corresponding to given phone id; null if there is no card present for
404      * the phone id
405      */
getUiccCardForPhone(int phoneId)406     public UiccCard getUiccCardForPhone(int phoneId) {
407         synchronized (mLock) {
408             if (isValidPhoneIndex(phoneId)) {
409                 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
410                 if (uiccSlot != null) {
411                     return uiccSlot.getUiccCard();
412                 }
413             }
414             return null;
415         }
416     }
417 
418     /**
419      * API to get UiccPort corresponding to given phone id
420      * @return UiccPort object corresponding to given phone id; null if there is no card present for
421      * the phone id
422      */
423     @Nullable
getUiccPortForPhone(int phoneId)424     public UiccPort getUiccPortForPhone(int phoneId) {
425         synchronized (mLock) {
426             if (isValidPhoneIndex(phoneId)) {
427                 UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
428                 if (uiccSlot != null) {
429                     UiccCard uiccCard = uiccSlot.getUiccCard();
430                     if (uiccCard != null) {
431                         return uiccCard.getUiccPortForPhone(phoneId);
432                     }
433                 }
434             }
435             return null;
436         }
437     }
438 
439     /**
440      * API to get UiccProfile corresponding to given phone id
441      * @return UiccProfile object corresponding to given phone id; null if there is no card/profile
442      * present for the phone id
443      */
getUiccProfileForPhone(int phoneId)444     public UiccProfile getUiccProfileForPhone(int phoneId) {
445         synchronized (mLock) {
446             if (isValidPhoneIndex(phoneId)) {
447                 UiccPort uiccPort = getUiccPortForPhone(phoneId);
448                 return uiccPort != null ? uiccPort.getUiccProfile() : null;
449             }
450             return null;
451         }
452     }
453 
454     /**
455      * API to get all the UICC slots.
456      * @return UiccSlots array.
457      */
getUiccSlots()458     public UiccSlot[] getUiccSlots() {
459         synchronized (mLock) {
460             return mUiccSlots;
461         }
462     }
463 
464     /** Map logicalSlot to physicalSlot, portIndex and activate the physicalSlot with portIndex if
465      *  it is inactive. */
switchSlots(List<UiccSlotMapping> slotMapping, Message response)466     public void switchSlots(List<UiccSlotMapping> slotMapping, Message response) {
467         logWithLocalLog("switchSlots: " + slotMapping);
468         mRadioConfig.setSimSlotsMapping(slotMapping, response);
469     }
470 
471     /**
472      * API to get UiccSlot object for a specific physical slot index on the device
473      * @return UiccSlot object for the given physical slot index
474      */
getUiccSlot(int slotId)475     public UiccSlot getUiccSlot(int slotId) {
476         synchronized (mLock) {
477             if (isValidSlotIndex(slotId)) {
478                 return mUiccSlots[slotId];
479             }
480             return null;
481         }
482     }
483 
484     /**
485      * API to get UiccSlot object for a given phone id
486      * @return UiccSlot object for the given phone id
487      */
getUiccSlotForPhone(int phoneId)488     public UiccSlot getUiccSlotForPhone(int phoneId) {
489         synchronized (mLock) {
490             if (isValidPhoneIndex(phoneId)) {
491                 int slotId = getSlotIdFromPhoneId(phoneId);
492                 if (isValidSlotIndex(slotId)) {
493                     return mUiccSlots[slotId];
494                 }
495             }
496             return null;
497         }
498     }
499 
500     /**
501      * API to get UiccSlot object for a given cardId
502      * @param cardId Identifier for a SIM. This can be an ICCID, or an EID in case of an eSIM.
503      * @return int Index of UiccSlot for the given cardId if one is found, {@link #INVALID_SLOT_ID}
504      * otherwise
505      */
getUiccSlotForCardId(String cardId)506     public int getUiccSlotForCardId(String cardId) {
507         synchronized (mLock) {
508             // first look up based on cardId
509             for (int idx = 0; idx < mUiccSlots.length; idx++) {
510                 if (mUiccSlots[idx] != null) {
511                     UiccCard uiccCard = mUiccSlots[idx].getUiccCard();
512                     if (uiccCard != null && cardId.equals(uiccCard.getCardId())) {
513                         return idx;
514                     }
515                 }
516             }
517             // if a match is not found, do a lookup based on ICCID
518             for (int idx = 0; idx < mUiccSlots.length; idx++) {
519                 UiccSlot slot = mUiccSlots[idx];
520                 if (slot != null) {
521                     if (IntStream.of(slot.getPortList()).anyMatch(porIdx -> cardId.equals(
522                             slot.getIccId(porIdx)))) {
523                         return idx;
524                     }
525                 }
526             }
527             return INVALID_SLOT_ID;
528         }
529     }
530 
531     // Easy to use API
532     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getIccRecords(int phoneId, int family)533     public IccRecords getIccRecords(int phoneId, int family) {
534         synchronized (mLock) {
535             UiccCardApplication app = getUiccCardApplication(phoneId, family);
536             if (app != null) {
537                 return app.getIccRecords();
538             }
539             return null;
540         }
541     }
542 
543     // Easy to use API
544     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getIccFileHandler(int phoneId, int family)545     public IccFileHandler getIccFileHandler(int phoneId, int family) {
546         synchronized (mLock) {
547             UiccCardApplication app = getUiccCardApplication(phoneId, family);
548             if (app != null) {
549                 return app.getIccFileHandler();
550             }
551             return null;
552         }
553     }
554 
555 
556     //Notifies when card status changes
557     @UnsupportedAppUsage
registerForIccChanged(Handler h, int what, Object obj)558     public void registerForIccChanged(Handler h, int what, Object obj) {
559         synchronized (mLock) {
560             mIccChangedRegistrants.addUnique(h, what, obj);
561         }
562         //Notify registrant right after registering, so that it will get the latest ICC status,
563         //otherwise which may not happen until there is an actual change in ICC status.
564         Message.obtain(h, what, new AsyncResult(obj, null, null)).sendToTarget();
565     }
566 
unregisterForIccChanged(Handler h)567     public void unregisterForIccChanged(Handler h) {
568         synchronized (mLock) {
569             mIccChangedRegistrants.remove(h);
570         }
571     }
572 
573     @Override
handleMessage(Message msg)574     public void handleMessage (Message msg) {
575         synchronized (mLock) {
576             Integer phoneId = getCiIndex(msg);
577             String eventName = eventToString(msg.what);
578 
579             if (phoneId < 0 || phoneId >= mCis.length) {
580                 Rlog.e(LOG_TAG, "Invalid phoneId : " + phoneId + " received with event "
581                         + eventName);
582                 return;
583             }
584 
585             logWithLocalLog("handleMessage: Received " + eventName + " for phoneId " + phoneId);
586 
587             AsyncResult ar = (AsyncResult)msg.obj;
588             switch (msg.what) {
589                 case EVENT_ICC_STATUS_CHANGED:
590                     if (DBG) log("Received EVENT_ICC_STATUS_CHANGED, calling getIccCardStatus");
591                     mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
592                             phoneId));
593                     break;
594                 case EVENT_RADIO_AVAILABLE:
595                 case EVENT_RADIO_ON:
596                     if (DBG) {
597                         log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON, calling "
598                                 + "getIccCardStatus");
599                     }
600                     // slot status should be the same on all RILs; request it only for phoneId 0
601                     if (phoneId == 0) {
602                         if (DBG) {
603                             log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, "
604                                     + "calling getSimSlotsStatus");
605                         }
606                         mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,
607                                 phoneId));
608                     }
609                     mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
610                             phoneId));
611                     break;
612                 case EVENT_GET_ICC_STATUS_DONE:
613                     if (DBG) log("Received EVENT_GET_ICC_STATUS_DONE");
614                     onGetIccCardStatusDone(ar, phoneId);
615                     break;
616                 case EVENT_SLOT_STATUS_CHANGED:
617                 case EVENT_GET_SLOT_STATUS_DONE:
618                     if (DBG) {
619                         log("Received EVENT_SLOT_STATUS_CHANGED or EVENT_GET_SLOT_STATUS_DONE");
620                     }
621                     onGetSlotStatusDone(ar);
622                     break;
623                 case EVENT_RADIO_UNAVAILABLE:
624                     if (DBG) log("EVENT_RADIO_UNAVAILABLE, dispose card");
625                     sLastSlotStatus = null;
626                     UiccSlot uiccSlot = getUiccSlotForPhone(phoneId);
627                     if (uiccSlot != null) {
628                         uiccSlot.onRadioStateUnavailable(phoneId);
629                     }
630                     mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, phoneId, null));
631                     break;
632                 case EVENT_SIM_REFRESH:
633                     if (DBG) log("Received EVENT_SIM_REFRESH");
634                     onSimRefresh(ar, phoneId);
635                     break;
636                 case EVENT_EID_READY:
637                     if (DBG) log("Received EVENT_EID_READY");
638                     onEidReady(ar, phoneId);
639                     break;
640                 case EVENT_MULTI_SIM_CONFIG_CHANGED:
641                     if (DBG) log("Received EVENT_MULTI_SIM_CONFIG_CHANGED");
642                     int activeModemCount = (int) ((AsyncResult) msg.obj).result;
643                     onMultiSimConfigChanged(activeModemCount);
644                     break;
645                 default:
646                     Rlog.e(LOG_TAG, " Unknown Event " + msg.what);
647                     break;
648             }
649         }
650     }
651 
onMultiSimConfigChanged(int newActiveModemCount)652     private void onMultiSimConfigChanged(int newActiveModemCount) {
653         int prevActiveModemCount = mCis.length;
654         mCis = PhoneFactory.getCommandsInterfaces();
655 
656         logWithLocalLog("onMultiSimConfigChanged: prevActiveModemCount " + prevActiveModemCount
657                 + ", newActiveModemCount " + newActiveModemCount);
658 
659         // Resize array.
660         mPhoneIdToSlotId = copyOf(mPhoneIdToSlotId, newActiveModemCount);
661 
662         // Register for new active modem for ss -> ds switch.
663         // For ds -> ss switch, there's no need to unregister as the mCis should unregister
664         // everything itself.
665         for (int i = prevActiveModemCount; i < newActiveModemCount; i++) {
666             mPhoneIdToSlotId[i] = INVALID_SLOT_ID;
667             mCis[i].registerForIccStatusChanged(this, EVENT_ICC_STATUS_CHANGED, i);
668             mCis[i].registerForAvailable(this, EVENT_RADIO_AVAILABLE, i);
669             mCis[i].registerForNotAvailable(this, EVENT_RADIO_UNAVAILABLE, i);
670             mCis[i].registerForIccRefresh(this, EVENT_SIM_REFRESH, i);
671         }
672     }
673 
getCiIndex(Message msg)674     private Integer getCiIndex(Message msg) {
675         AsyncResult ar;
676         Integer index = new Integer(PhoneConstants.DEFAULT_SLOT_INDEX);
677 
678         /*
679          * The events can be come in two ways. By explicitly sending it using
680          * sendMessage, in this case the user object passed is msg.obj and from
681          * the CommandsInterface, in this case the user object is msg.obj.userObj
682          */
683         if (msg != null) {
684             if (msg.obj != null && msg.obj instanceof Integer) {
685                 index = (Integer)msg.obj;
686             } else if(msg.obj != null && msg.obj instanceof AsyncResult) {
687                 ar = (AsyncResult)msg.obj;
688                 if (ar.userObj != null && ar.userObj instanceof Integer) {
689                     index = (Integer)ar.userObj;
690                 }
691             }
692         }
693         return index;
694     }
695 
eventToString(int event)696     private static String eventToString(int event) {
697         switch (event) {
698             case EVENT_ICC_STATUS_CHANGED: return "ICC_STATUS_CHANGED";
699             case EVENT_SLOT_STATUS_CHANGED: return "SLOT_STATUS_CHANGED";
700             case EVENT_GET_ICC_STATUS_DONE: return "GET_ICC_STATUS_DONE";
701             case EVENT_GET_SLOT_STATUS_DONE: return "GET_SLOT_STATUS_DONE";
702             case EVENT_RADIO_ON: return "RADIO_ON";
703             case EVENT_RADIO_AVAILABLE: return "RADIO_AVAILABLE";
704             case EVENT_RADIO_UNAVAILABLE: return "RADIO_UNAVAILABLE";
705             case EVENT_SIM_REFRESH: return "SIM_REFRESH";
706             case EVENT_EID_READY: return "EID_READY";
707             case EVENT_MULTI_SIM_CONFIG_CHANGED: return "MULTI_SIM_CONFIG_CHANGED";
708             default: return "UNKNOWN(" + event + ")";
709         }
710     }
711 
712     // Easy to use API
713     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getUiccCardApplication(int phoneId, int family)714     public UiccCardApplication getUiccCardApplication(int phoneId, int family) {
715         synchronized (mLock) {
716             UiccPort uiccPort = getUiccPortForPhone(phoneId);
717             if (uiccPort != null) {
718                 return uiccPort.getApplication(family);
719             }
720             return null;
721         }
722     }
723 
724     /**
725      * Convert IccCardConstants.State enum values to corresponding IccCardConstants String
726      * constants
727      * @param state IccCardConstants.State enum value
728      * @return IccCardConstants String constant representing ICC state
729      */
getIccStateIntentString(IccCardConstants.State state)730     public static String getIccStateIntentString(IccCardConstants.State state) {
731         switch (state) {
732             case ABSENT: return IccCardConstants.INTENT_VALUE_ICC_ABSENT;
733             case PIN_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
734             case PUK_REQUIRED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
735             case NETWORK_LOCKED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
736             case READY: return IccCardConstants.INTENT_VALUE_ICC_READY;
737             case NOT_READY: return IccCardConstants.INTENT_VALUE_ICC_NOT_READY;
738             case PERM_DISABLED: return IccCardConstants.INTENT_VALUE_ICC_LOCKED;
739             case CARD_IO_ERROR: return IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR;
740             case CARD_RESTRICTED: return IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED;
741             case LOADED: return IccCardConstants.INTENT_VALUE_ICC_LOADED;
742             default: return IccCardConstants.INTENT_VALUE_ICC_UNKNOWN;
743         }
744     }
745 
746     /**
747      * Update SIM state for the inactive eSIM port.
748      *
749      * @param phoneId Previously active phone id.
750      * @param iccId ICCID of the SIM.
751      */
updateSimStateForInactivePort(int phoneId, String iccId)752     public void updateSimStateForInactivePort(int phoneId, String iccId) {
753         post(() -> {
754             if (SubscriptionManager.isValidPhoneId(phoneId)) {
755                 // Mark SIM state as ABSENT on previously phoneId.
756                 mTelephonyManager.setSimStateForPhone(phoneId,
757                         IccCardConstants.State.ABSENT.toString());
758             }
759 
760             SubscriptionManagerService.getInstance().updateSimStateForInactivePort(phoneId,
761                     TextUtils.emptyIfNull(iccId));
762         });
763     }
764 
765     /**
766      * Broadcast the legacy SIM state changed event.
767      *
768      * @param phoneId The phone id.
769      * @param state The legacy SIM state.
770      * @param reason The reason of SIM state change.
771      */
broadcastSimStateChanged(int phoneId, @NonNull String state, @Nullable String reason)772     private void broadcastSimStateChanged(int phoneId, @NonNull String state,
773             @Nullable String reason) {
774         // Note: This intent is way deprecated and is only being kept around because there's no
775         // graceful way to deprecate a sticky broadcast that has a lot of listeners.
776         // DO NOT add any new extras to this broadcast -- it is not protected by any permissions.
777         Intent intent = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
778         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
779         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
780         intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
781         intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
782         intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
783         SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
784         Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason "
785                 + reason + " for phone: " + phoneId);
786         IntentBroadcaster.getInstance().broadcastStickyIntent(mContext, intent, phoneId);
787     }
788 
789     /**
790      * Broadcast SIM card state changed event.
791      *
792      * @param phoneId The phone id.
793      * @param state The SIM card state.
794      */
broadcastSimCardStateChanged(int phoneId, @SimState int state)795     private void broadcastSimCardStateChanged(int phoneId, @SimState int state) {
796         if (state != mSimCardState[phoneId]) {
797             mSimCardState[phoneId] = state;
798             Intent intent = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
799             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
800             intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
801             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
802             // TODO(b/130664115) we manually populate this intent with the slotId. In the future we
803             // should do a review of whether to make this public
804             UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
805             int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId);
806             intent.putExtra(PhoneConstants.SLOT_KEY, slotId);
807             int portIndex = -1;
808             if (slot != null) {
809                 portIndex = slot.getPortIndexFromPhoneId(phoneId);
810                 intent.putExtra(PhoneConstants.PORT_KEY, portIndex);
811             }
812             Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED "
813                     + TelephonyManager.simStateToString(state) + " for phone: " + phoneId
814                     + " slot: " + slotId + " port: " + portIndex);
815             mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
816             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
817         }
818     }
819 
820     /**
821      * Broadcast SIM application state changed event.
822      *
823      * @param phoneId The phone id.
824      * @param state The SIM application state.
825      */
broadcastSimApplicationStateChanged(int phoneId, @SimState int state)826     private void broadcastSimApplicationStateChanged(int phoneId, @SimState int state) {
827         // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY,
828         // because that's the initial state and a broadcast should be sent only on a transition
829         // after SIM is PRESENT. The only exception is eSIM boot profile, where NOT_READY is the
830         // terminal state.
831         boolean isUnknownToNotReady =
832                 (mSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN
833                         && state == TelephonyManager.SIM_STATE_NOT_READY);
834         IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard();
835         boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile();
836         if (state != mSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) {
837             mSimApplicationState[phoneId] = state;
838             Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
839             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
840             intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
841             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
842             // TODO(b/130664115) we populate this intent with the actual slotId. In the future we
843             // should do a review of whether to make this public
844             UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
845             int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId);
846             intent.putExtra(PhoneConstants.SLOT_KEY, slotId);
847             if (slot != null) {
848                 intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId));
849             }
850             Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED "
851                     + TelephonyManager.simStateToString(state)
852                     + " for phone: " + phoneId + " slot: " + slotId + "port: "
853                     + slot.getPortIndexFromPhoneId(phoneId));
854             mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
855             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
856         }
857     }
858 
859     /**
860      * Get SIM state from SIM lock reason.
861      *
862      * @param lockedReason The SIM lock reason.
863      *
864      * @return The SIM state.
865      */
866     @SimState
getSimStateFromLockedReason(String lockedReason)867     private static int getSimStateFromLockedReason(String lockedReason) {
868         switch (lockedReason) {
869             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN:
870                 return TelephonyManager.SIM_STATE_PIN_REQUIRED;
871             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK:
872                 return TelephonyManager.SIM_STATE_PUK_REQUIRED;
873             case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK:
874                 return TelephonyManager.SIM_STATE_NETWORK_LOCKED;
875             case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED:
876                 return TelephonyManager.SIM_STATE_PERM_DISABLED;
877             default:
878                 Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason);
879                 return TelephonyManager.SIM_STATE_UNKNOWN;
880         }
881     }
882 
883     /**
884      * Broadcast SIM state events.
885      *
886      * @param phoneId The phone id.
887      * @param simState The SIM state.
888      * @param reason SIM state changed reason.
889      */
broadcastSimStateEvents(int phoneId, IccCardConstants.State simState, @Nullable String reason)890     private void broadcastSimStateEvents(int phoneId, IccCardConstants.State simState,
891             @Nullable String reason) {
892         String legacyStringSimState = getIccStateIntentString(simState);
893         int cardState = TelephonyManager.SIM_STATE_UNKNOWN;
894         int applicationState = TelephonyManager.SIM_STATE_UNKNOWN;
895 
896         switch (simState) {
897             case ABSENT:
898                 cardState = TelephonyManager.SIM_STATE_ABSENT;
899                 break;
900             case PIN_REQUIRED:
901             case PUK_REQUIRED:
902             case NETWORK_LOCKED:
903             case PERM_DISABLED:
904                 cardState = TelephonyManager.SIM_STATE_PRESENT;
905                 applicationState = getSimStateFromLockedReason(reason);
906                 break;
907             case READY:
908             case NOT_READY:
909                 // Both READY and NOT_READY have the same card state and application state.
910                 cardState = TelephonyManager.SIM_STATE_PRESENT;
911                 applicationState = TelephonyManager.SIM_STATE_NOT_READY;
912                 break;
913             case CARD_IO_ERROR:
914                 cardState = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
915                 applicationState = TelephonyManager.SIM_STATE_NOT_READY;
916                 break;
917             case CARD_RESTRICTED:
918                 cardState = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
919                 applicationState = TelephonyManager.SIM_STATE_NOT_READY;
920                 break;
921             case LOADED:
922                 cardState = TelephonyManager.SIM_STATE_PRESENT;
923                 applicationState = TelephonyManager.SIM_STATE_LOADED;
924                 break;
925             case UNKNOWN:
926             default:
927                 break;
928         }
929 
930         broadcastSimStateChanged(phoneId, legacyStringSimState, reason);
931         broadcastSimCardStateChanged(phoneId, cardState);
932         broadcastSimApplicationStateChanged(phoneId, applicationState);
933     }
934 
935     /**
936      * Update carrier service.
937      *
938      * @param phoneId The phone id.
939      * @param simState The SIM state.
940      */
updateCarrierServices(int phoneId, @NonNull String simState)941     private void updateCarrierServices(int phoneId, @NonNull String simState) {
942         CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
943         if (configManager != null) {
944             configManager.updateConfigForPhoneId(phoneId, simState);
945         }
946         mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState);
947     }
948 
949     /**
950      * Update the SIM state.
951      *
952      * @param phoneId Phone id.
953      * @param state SIM state (legacy).
954      * @param reason The reason for SIM state update.
955      */
updateSimState(int phoneId, @NonNull IccCardConstants.State state, @Nullable String reason)956     public void updateSimState(int phoneId, @NonNull IccCardConstants.State state,
957             @Nullable String reason) {
958         post(() -> {
959             log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason="
960                     + reason);
961             if (!SubscriptionManager.isValidPhoneId(phoneId)) {
962                 Rlog.e(LOG_TAG, "updateSimState: Invalid phone id " + phoneId);
963                 return;
964             }
965 
966             mTelephonyManager.setSimStateForPhone(phoneId, state.toString());
967 
968             String legacySimState = getIccStateIntentString(state);
969             int simState = state.ordinal();
970             SubscriptionManagerService.getInstance().updateSimState(phoneId, simState,
971                     this::post,
972                     () -> {
973                         // The following are executed after subscription update completed in
974                         // subscription manager service.
975 
976                         broadcastSimStateEvents(phoneId, state, reason);
977 
978                         UiccProfile uiccProfile = getUiccProfileForPhone(phoneId);
979 
980                         if (simState == TelephonyManager.SIM_STATE_READY) {
981                             // SIM_STATE_READY is not a final state.
982                             return;
983                         }
984 
985                         if (simState == TelephonyManager.SIM_STATE_NOT_READY
986                                 && (uiccProfile != null && !uiccProfile.isEmptyProfile())
987                                 && SubscriptionManagerService.getInstance()
988                                 .areUiccAppsEnabledOnCard(phoneId)) {
989                             // STATE_NOT_READY is not a final state for when both
990                             // 1) It's not an empty profile, and
991                             // 2) Its uicc applications are set to enabled.
992                             //
993                             // At this phase, we consider STATE_NOT_READY not a final state, so
994                             // return for now.
995                             log("updateSimState: SIM_STATE_NOT_READY is not a final "
996                                     + "state.");
997                             return;
998                         }
999 
1000                         if (!SubscriptionManager.isValidPhoneId(phoneId)) {
1001                             Rlog.e(LOG_TAG, "updateSimState: Cannot update carrier services. "
1002                                     + "Invalid phone id " + phoneId);
1003                             return;
1004                         }
1005 
1006                         // At this point, the SIM state must be a final state (meaning we won't
1007                         // get more SIM state updates). So resolve the carrier id and update the
1008                         // carrier services.
1009                         log("updateSimState: resolve carrier id and update carrier "
1010                                 + "services.");
1011                         PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId(
1012                                 legacySimState);
1013                         updateCarrierServices(phoneId, legacySimState);
1014                     }
1015             );
1016         });
1017     }
1018 
onGetIccCardStatusDone(AsyncResult ar, Integer index)1019     private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
1020         if (ar.exception != null) {
1021             Rlog.e(LOG_TAG,"Error getting ICC status. "
1022                     + "RIL_REQUEST_GET_ICC_STATUS should "
1023                     + "never return an error", ar.exception);
1024             return;
1025         }
1026         if (!isValidPhoneIndex(index)) {
1027             Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
1028             return;
1029         }
1030         if (isShuttingDown()) {
1031             // Do not process the SIM/SLOT events during device shutdown,
1032             // as it may unnecessarily modify the persistent information
1033             // like, SubscriptionManager.UICC_APPLICATIONS_ENABLED.
1034             log("onGetIccCardStatusDone: shudown in progress ignore event");
1035             return;
1036         }
1037 
1038         IccCardStatus status = (IccCardStatus)ar.result;
1039 
1040         logWithLocalLog("onGetIccCardStatusDone: phoneId-" + index + " IccCardStatus: " + status);
1041 
1042         int slotId = status.mSlotPortMapping.mPhysicalSlotIndex;
1043         if (VDBG) log("onGetIccCardStatusDone: phoneId-" + index + " physicalSlotIndex " + slotId);
1044         if (slotId == INVALID_SLOT_ID) {
1045             slotId = index;
1046         }
1047 
1048         mPhoneIdToSlotId[index] = slotId;
1049 
1050         if (VDBG) logPhoneIdToSlotIdMapping();
1051 
1052         if (mUiccSlots[slotId] == null) {
1053             if (VDBG) {
1054                 log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = "
1055                         + mUiccSlots.length);
1056             }
1057             mUiccSlots[slotId] = new UiccSlot(mContext, true);
1058         }
1059 
1060         mUiccSlots[slotId].update(mCis[index], status, index, slotId);
1061 
1062         UiccCard card = mUiccSlots[slotId].getUiccCard();
1063         if (card == null) {
1064             if (DBG) log("mUiccSlots[" + slotId + "] has no card. Notifying IccChangedRegistrants");
1065             mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
1066             return;
1067         }
1068 
1069         UiccPort port = card.getUiccPort(status.mSlotPortMapping.mPortIndex);
1070         if (port == null) {
1071             if (DBG) log("mUiccSlots[" + slotId + "] has no UiccPort with index["
1072                     + status.mSlotPortMapping.mPortIndex + "]. Notifying IccChangedRegistrants");
1073             mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
1074             return;
1075         }
1076 
1077         String cardString = null;
1078         boolean isEuicc = mUiccSlots[slotId].isEuicc();
1079         if (isEuicc) {
1080             cardString = ((EuiccCard) card).getEid();
1081         } else {
1082             cardString = card.getUiccPort(status.mSlotPortMapping.mPortIndex).getIccId();
1083         }
1084 
1085         if (cardString != null) {
1086             addCardId(cardString);
1087         }
1088 
1089         // EID is unpopulated if Radio HAL < 1.4 (RadioConfig < 1.2)
1090         // If so, just register for EID loaded and skip this stuff
1091         if (isEuicc && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) {
1092             if (cardString == null) {
1093                 ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index);
1094             } else {
1095                 // If we know the EID from IccCardStatus, just use it to set mDefaultEuiccCardId if
1096                 // it's not already set.
1097                 // This is needed in cases where slot status doesn't include EID, and we don't want
1098                 // to register for EID from APDU because we already know cardString from a previous
1099                 // APDU
1100                 if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
1101                         || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1102                     mDefaultEuiccCardId = convertToPublicCardId(cardString);
1103                     logWithLocalLog("IccCardStatus eid="
1104                             + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, cardString) + " slot=" + slotId
1105                             + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1106                 }
1107             }
1108         }
1109 
1110         if (DBG) log("Notifying IccChangedRegistrants");
1111         mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
1112     }
1113 
1114     /**
1115      * Add a cardString to mCardStrings. If this is an ICCID, trailing Fs will be automatically
1116      * stripped.
1117      */
addCardId(String cardString)1118     private void addCardId(String cardString) {
1119         if (TextUtils.isEmpty(cardString)) {
1120             return;
1121         }
1122         if (cardString.length() < EID_LENGTH) {
1123             cardString = IccUtils.stripTrailingFs(cardString);
1124         }
1125         if (!mCardStrings.contains(cardString)) {
1126             mCardStrings.add(cardString);
1127             saveCardStrings();
1128         }
1129     }
1130 
1131     /**
1132      * Converts an integer cardId (public card ID) to a card string.
1133      * @param cardId to convert
1134      * @return cardString, or null if the cardId is not valid
1135      */
convertToCardString(int cardId)1136     public String convertToCardString(int cardId) {
1137         if (cardId < 0 || cardId >= mCardStrings.size()) {
1138             log("convertToCardString: cardId " + cardId + " is not valid");
1139             return null;
1140         }
1141         return mCardStrings.get(cardId);
1142     }
1143 
1144     /**
1145      * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId.
1146      * If the given cardString is an ICCID, trailing Fs will be automatically stripped before trying
1147      * to match to a card ID.
1148      *
1149      * @return the matching cardId, or UNINITIALIZED_CARD_ID if the card string does not map to a
1150      * currently loaded cardId, or UNSUPPORTED_CARD_ID if the device does not support card IDs
1151      */
convertToPublicCardId(String cardString)1152     public int convertToPublicCardId(String cardString) {
1153         if (mDefaultEuiccCardId == UNSUPPORTED_CARD_ID) {
1154             // even if cardString is not an EID, if EID is not supported (e.g. HAL < 1.2) we can't
1155             // guarentee a working card ID implementation, so return UNSUPPORTED_CARD_ID
1156             return UNSUPPORTED_CARD_ID;
1157         }
1158         if (TextUtils.isEmpty(cardString)) {
1159             return UNINITIALIZED_CARD_ID;
1160         }
1161 
1162         if (cardString.length() < EID_LENGTH) {
1163             cardString = IccUtils.stripTrailingFs(cardString);
1164         }
1165         int id = mCardStrings.indexOf(cardString);
1166         if (id == -1) {
1167             return UNINITIALIZED_CARD_ID;
1168         } else {
1169             return id;
1170         }
1171     }
1172 
1173     /**
1174      * Returns the UiccCardInfo of all currently inserted UICCs and embedded eUICCs.
1175      */
getAllUiccCardInfos()1176     public ArrayList<UiccCardInfo> getAllUiccCardInfos() {
1177         synchronized (mLock) {
1178             ArrayList<UiccCardInfo> infos = new ArrayList<>();
1179             for (int slotIndex = 0; slotIndex < mUiccSlots.length; slotIndex++) {
1180                 final UiccSlot slot = mUiccSlots[slotIndex];
1181                 if (slot == null) continue;
1182                 boolean isEuicc = slot.isEuicc();
1183                 String eid = null;
1184                 UiccCard card = slot.getUiccCard();
1185                 int cardId = UNINITIALIZED_CARD_ID;
1186                 boolean isRemovable = slot.isRemovable();
1187 
1188                 // first we try to populate UiccCardInfo using the UiccCard, but if it doesn't exist
1189                 // (e.g. the slot is for an inactive eUICC) then we try using the UiccSlot.
1190                 if (card != null) {
1191                     if (isEuicc) {
1192                         eid = ((EuiccCard) card).getEid();
1193                         cardId = convertToPublicCardId(eid);
1194                     } else {
1195                         // In case of non Euicc, use default port index to get the IccId.
1196                         UiccPort port = card.getUiccPort(TelephonyManager.DEFAULT_PORT_INDEX);
1197                         if (port == null) {
1198                             AnomalyReporter.reportAnomaly(
1199                                     UUID.fromString("92885ba7-98bb-490a-ba19-987b1c8b2055"),
1200                                     "UiccController: Found UiccPort Null object.");
1201                         }
1202                         String iccId = (port != null) ? port.getIccId() : null;
1203                         cardId = convertToPublicCardId(iccId);
1204                     }
1205                 } else {
1206                     // This iccid is used for non Euicc only, so use default port index
1207                     String iccId = slot.getIccId(TelephonyManager.DEFAULT_PORT_INDEX);
1208                     // Fill in the fields we can
1209                     if (!isEuicc && !TextUtils.isEmpty(iccId)) {
1210                         cardId = convertToPublicCardId(iccId);
1211                     }
1212                 }
1213 
1214                 List<UiccPortInfo> portInfos = new ArrayList<>();
1215                 int[] portIndexes = slot.getPortList();
1216                 for (int portIdx : portIndexes) {
1217                     String iccId = IccUtils.stripTrailingFs(slot.getIccId(portIdx));
1218                     portInfos.add(new UiccPortInfo(iccId, portIdx,
1219                             slot.getPhoneIdFromPortIndex(portIdx), slot.isPortActive(portIdx)));
1220                 }
1221                 UiccCardInfo info = new UiccCardInfo(
1222                         isEuicc, cardId, eid, slotIndex, isRemovable,
1223                         slot.isMultipleEnabledProfileSupported(), portInfos);
1224                 infos.add(info);
1225             }
1226             return infos;
1227         }
1228     }
1229 
1230     /**
1231      * Get the card ID of the default eUICC.
1232      */
getCardIdForDefaultEuicc()1233     public int getCardIdForDefaultEuicc() {
1234         if (mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1235             return UNSUPPORTED_CARD_ID;
1236         }
1237         // To support removable eSIM to pass GCT/PTCRB test in DSDS mode, we should make sure all
1238         // the download/activation requests are by default route to the removable eSIM slot.
1239         // To satisfy above condition, we should return removable eSIM cardId as default.
1240         if (mUseRemovableEsimAsDefault && !TelephonyUtils.IS_USER) {
1241             for (UiccSlot slot : mUiccSlots) {
1242                 if (slot != null && slot.isRemovable() && slot.isEuicc() && slot.isActive()) {
1243                     int cardId = convertToPublicCardId(slot.getEid());
1244                     Rlog.d(LOG_TAG,
1245                             "getCardIdForDefaultEuicc: Removable eSIM is default, cardId: "
1246                                     + cardId);
1247                     return cardId;
1248                 }
1249             }
1250             Rlog.d(LOG_TAG, "getCardIdForDefaultEuicc: No removable eSIM slot is found");
1251         }
1252         return mDefaultEuiccCardId;
1253     }
1254 
1255     /** Get the {@link PinStorage}. */
getPinStorage()1256     public PinStorage getPinStorage() {
1257         return mPinStorage;
1258     }
1259 
loadCardStrings()1260     private ArrayList<String> loadCardStrings() {
1261         String cardStrings =
1262                 PreferenceManager.getDefaultSharedPreferences(mContext).getString(CARD_STRINGS, "");
1263         if (TextUtils.isEmpty(cardStrings)) {
1264             // just return an empty list, since String.split would return the list { "" }
1265             return new ArrayList<String>();
1266         }
1267         return new ArrayList<String>(Arrays.asList(cardStrings.split(",")));
1268     }
1269 
saveCardStrings()1270     private void saveCardStrings() {
1271         SharedPreferences.Editor editor =
1272                 PreferenceManager.getDefaultSharedPreferences(mContext).edit();
1273         editor.putString(CARD_STRINGS, TextUtils.join(",", mCardStrings));
1274         editor.commit();
1275     }
1276 
onGetSlotStatusDone(AsyncResult ar)1277     private synchronized void onGetSlotStatusDone(AsyncResult ar) {
1278         if (!mIsSlotStatusSupported) {
1279             if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false");
1280             return;
1281         }
1282         Throwable e = ar.exception;
1283         if (e != null) {
1284             if (!(e instanceof CommandException) || ((CommandException) e).getCommandError()
1285                     != CommandException.Error.REQUEST_NOT_SUPPORTED) {
1286                 // this is not expected; there should be no exception other than
1287                 // REQUEST_NOT_SUPPORTED
1288                 logeWithLocalLog("Unexpected error getting slot status: " + ar.exception);
1289             } else {
1290                 // REQUEST_NOT_SUPPORTED
1291                 logWithLocalLog("onGetSlotStatusDone: request not supported; marking "
1292                         + "mIsSlotStatusSupported to false");
1293                 mIsSlotStatusSupported = false;
1294             }
1295             return;
1296         }
1297         if (isShuttingDown()) {
1298             // Do not process the SIM/SLOT events during device shutdown,
1299             // as it may unnecessarily modify the persistent information
1300             // like, SubscriptionManager.UICC_APPLICATIONS_ENABLED.
1301             log("onGetSlotStatusDone: shudown in progress ignore event");
1302             return;
1303         }
1304 
1305         ArrayList<IccSlotStatus> status = (ArrayList<IccSlotStatus>) ar.result;
1306 
1307         if (!slotStatusChanged(status)) {
1308             log("onGetSlotStatusDone: No change in slot status");
1309             return;
1310         }
1311         logWithLocalLog("onGetSlotStatusDone: " + status);
1312 
1313         sLastSlotStatus = status;
1314 
1315         int numActivePorts = 0;
1316         boolean isDefaultEuiccCardIdSet = false;
1317         boolean anyEuiccIsActive = false;
1318         mHasActiveBuiltInEuicc = false;
1319 
1320         int numSlots = status.size();
1321         if (mUiccSlots.length < numSlots) {
1322             logeWithLocalLog("The number of the physical slots reported " + numSlots
1323                     + " is greater than the expectation " + mUiccSlots.length);
1324             numSlots = mUiccSlots.length;
1325         }
1326 
1327         for (int i = 0; i < numSlots; i++) {
1328             IccSlotStatus iss = status.get(i);
1329             boolean isActive = hasActivePort(iss.mSimPortInfos);
1330             if (mUiccSlots[i] == null) {
1331                 if (VDBG) {
1332                     log("Creating mUiccSlot[" + i + "]; mUiccSlots.length = " + mUiccSlots.length);
1333                 }
1334                 mUiccSlots[i] = new UiccSlot(mContext, isActive);
1335             }
1336 
1337             if (isActive) { // check isActive flag so that we don't have to iterate through all
1338                 for (int j = 0; j < iss.mSimPortInfos.length; j++) {
1339                     if (iss.mSimPortInfos[j].mPortActive) {
1340                         int logicalSlotIndex = iss.mSimPortInfos[j].mLogicalSlotIndex;
1341                         // Correctness check: logicalSlotIndex should be valid for an active slot
1342                         if (!isValidPhoneIndex(logicalSlotIndex)) {
1343                             Rlog.e(LOG_TAG, "Skipping slot " + i + " portIndex " + j + " as phone "
1344                                     + logicalSlotIndex
1345                                     + " is not available to communicate with this slot");
1346                         } else {
1347                             mPhoneIdToSlotId[logicalSlotIndex] = i;
1348                         }
1349                         numActivePorts++;
1350                     }
1351                 }
1352             }
1353 
1354             mUiccSlots[i].update(mCis, iss, i);
1355 
1356             if (mUiccSlots[i].isEuicc()) {
1357                 if (isActive) {
1358                     anyEuiccIsActive = true;
1359 
1360                     if (isBuiltInEuiccSlot(i)) {
1361                         mHasActiveBuiltInEuicc = true;
1362                     }
1363                 }
1364                 String eid = iss.eid;
1365                 if (TextUtils.isEmpty(eid)) {
1366                     // iss.eid is not populated on HAL<1.4
1367                     continue;
1368                 }
1369 
1370                 addCardId(eid);
1371 
1372                 // whenever slot status is received, set default card to the non-removable eUICC
1373                 // with the lowest slot index.
1374                 if (!mUiccSlots[i].isRemovable() && !isDefaultEuiccCardIdSet) {
1375                     isDefaultEuiccCardIdSet = true;
1376                     mDefaultEuiccCardId = convertToPublicCardId(eid);
1377                     logWithLocalLog("Using eid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1378                             + " in slot=" + i + " to set mDefaultEuiccCardId="
1379                             + mDefaultEuiccCardId);
1380                 }
1381             }
1382         }
1383 
1384         if (!mHasActiveBuiltInEuicc && !isDefaultEuiccCardIdSet) {
1385             // if there are no active built-in eUICCs, then consider setting a removable eUICC to
1386             // the default.
1387             // Note that on HAL<1.2, it's possible that a built-in eUICC exists, but does not
1388             // correspond to any slot in mUiccSlots. This logic is still safe in that case because
1389             // SlotStatus is only for HAL >= 1.2
1390             for (int i = 0; i < numSlots; i++) {
1391                 if (mUiccSlots[i].isEuicc()) {
1392                     String eid = status.get(i).eid;
1393                     if (!TextUtils.isEmpty(eid)) {
1394                         isDefaultEuiccCardIdSet = true;
1395                         mDefaultEuiccCardId = convertToPublicCardId(eid);
1396                         logWithLocalLog("Using eid="
1397                                 + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1398                                 + " from removable eUICC in slot=" + i
1399                                 + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1400                         break;
1401                     }
1402                 }
1403             }
1404         }
1405 
1406         if (mHasBuiltInEuicc && !anyEuiccIsActive && !isDefaultEuiccCardIdSet) {
1407             logWithLocalLog(
1408                     "onGetSlotStatusDone: mDefaultEuiccCardId=TEMPORARILY_UNSUPPORTED_CARD_ID");
1409             isDefaultEuiccCardIdSet = true;
1410             mDefaultEuiccCardId = TEMPORARILY_UNSUPPORTED_CARD_ID;
1411         }
1412 
1413 
1414         if (!isDefaultEuiccCardIdSet) {
1415             if (mDefaultEuiccCardId >= 0) {
1416                 // if mDefaultEuiccCardId has already been set to an actual eUICC,
1417                 // don't overwrite mDefaultEuiccCardId unless that eUICC is no longer inserted
1418                 boolean defaultEuiccCardIdIsStillInserted = false;
1419                 String cardString = mCardStrings.get(mDefaultEuiccCardId);
1420                 for (UiccSlot slot : mUiccSlots) {
1421                     if (slot.getUiccCard() == null) {
1422                         continue;
1423                     }
1424                     if (cardString.equals(
1425                             IccUtils.stripTrailingFs(slot.getUiccCard().getCardId()))) {
1426                         defaultEuiccCardIdIsStillInserted = true;
1427                     }
1428                 }
1429                 if (!defaultEuiccCardIdIsStillInserted) {
1430                     logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId="
1431                             + mDefaultEuiccCardId
1432                             + " is no longer inserted. Setting mDefaultEuiccCardId=UNINITIALIZED");
1433                     mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1434                 }
1435             } else {
1436                 // no known eUICCs at all (it's possible that an eUICC is inserted and we just don't
1437                 // know it's EID)
1438                 logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId=UNINITIALIZED");
1439                 mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1440             }
1441         }
1442 
1443         if (VDBG) logPhoneIdToSlotIdMapping();
1444 
1445         // Correctness check: number of active ports should be valid
1446         if (numActivePorts != mPhoneIdToSlotId.length) {
1447             Rlog.e(LOG_TAG, "Number of active ports " + numActivePorts
1448                        + " does not match the number of Phones" + mPhoneIdToSlotId.length);
1449         }
1450 
1451         // broadcast slot status changed
1452         final BroadcastOptions options = BroadcastOptions.makeBasic();
1453         options.setBackgroundActivityStartsAllowed(true);
1454         Intent intent = new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED);
1455         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1456         mContext.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1457                 options.toBundle());
1458     }
1459 
hasActivePort(IccSimPortInfo[] simPortInfos)1460     private boolean hasActivePort(IccSimPortInfo[] simPortInfos) {
1461         for (IccSimPortInfo simPortInfo : simPortInfos) {
1462             if (simPortInfo.mPortActive) {
1463                 return true;
1464             }
1465         }
1466         return false;
1467     }
1468 
1469     /**
1470      * Check if slot status has changed from the last received one
1471      */
1472     @VisibleForTesting
slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList)1473     public boolean slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList) {
1474         if (sLastSlotStatus == null || sLastSlotStatus.size() != slotStatusList.size()) {
1475             return true;
1476         }
1477         for (int i = 0; i < slotStatusList.size(); i++) {
1478             if (!sLastSlotStatus.get(i).equals(slotStatusList.get(i))) {
1479                 return true;
1480             }
1481         }
1482         return false;
1483     }
1484 
logPhoneIdToSlotIdMapping()1485     private void logPhoneIdToSlotIdMapping() {
1486         log("mPhoneIdToSlotId mapping:");
1487         for (int i = 0; i < mPhoneIdToSlotId.length; i++) {
1488             log("    phoneId " + i + " slotId " + mPhoneIdToSlotId[i]);
1489         }
1490     }
1491 
onSimRefresh(AsyncResult ar, Integer index)1492     private void onSimRefresh(AsyncResult ar, Integer index) {
1493         if (ar.exception != null) {
1494             Rlog.e(LOG_TAG, "onSimRefresh: Sim REFRESH with exception: " + ar.exception);
1495             return;
1496         }
1497 
1498         if (!isValidPhoneIndex(index)) {
1499             Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index);
1500             return;
1501         }
1502 
1503         IccRefreshResponse resp = (IccRefreshResponse) ar.result;
1504         logWithLocalLog("onSimRefresh: index " + index + ", " + resp);
1505 
1506         if (resp == null) {
1507             Rlog.e(LOG_TAG, "onSimRefresh: received without input");
1508             return;
1509         }
1510 
1511         UiccCard uiccCard = getUiccCardForPhone(index);
1512         if (uiccCard == null) {
1513             Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index);
1514             return;
1515         }
1516 
1517         UiccPort uiccPort = getUiccPortForPhone(index);
1518         if (uiccPort == null) {
1519             Rlog.e(LOG_TAG, "onSimRefresh: refresh on null port : " + index);
1520             return;
1521         }
1522 
1523         boolean changed = false;
1524         switch(resp.refreshResult) {
1525             // Reset the required apps when we know about the refresh so that
1526             // anyone interested does not get stale state.
1527             case IccRefreshResponse.REFRESH_RESULT_RESET:
1528                 changed = uiccPort.resetAppWithAid(resp.aid, true /* reset */);
1529                 break;
1530             case IccRefreshResponse.REFRESH_RESULT_INIT:
1531                 // don't dispose CatService on SIM REFRESH of type INIT
1532                 changed = uiccPort.resetAppWithAid(resp.aid, false /* initialize */);
1533                 break;
1534             default:
1535                 return;
1536         }
1537 
1538         if (changed && resp.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
1539             // If there is any change on RESET, reset carrier config as well. From carrier config
1540             // perspective, this is treated the same as sim state unknown
1541             CarrierConfigManager configManager = (CarrierConfigManager)
1542                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1543             configManager.updateConfigForPhoneId(index, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
1544         }
1545 
1546         // The card status could have changed. Get the latest state.
1547         mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
1548     }
1549 
1550     // for HAL 1.2-1.3 we register for EID ready, set mCardStrings and mDefaultEuiccCardId here.
1551     // Note that if there are multiple eUICCs on HAL 1.2-1.3, the default eUICC is the one whose EID
1552     // is first loaded
onEidReady(AsyncResult ar, Integer index)1553     private void onEidReady(AsyncResult ar, Integer index) {
1554         if (ar.exception != null) {
1555             Rlog.e(LOG_TAG, "onEidReady: exception: " + ar.exception);
1556             return;
1557         }
1558 
1559         if (!isValidPhoneIndex(index)) {
1560             Rlog.e(LOG_TAG, "onEidReady: invalid index: " + index);
1561             return;
1562         }
1563         int slotId = mPhoneIdToSlotId[index];
1564         EuiccCard card = (EuiccCard) mUiccSlots[slotId].getUiccCard();
1565         if (card == null) {
1566             Rlog.e(LOG_TAG, "onEidReady: UiccCard in slot " + slotId + " is null");
1567             return;
1568         }
1569 
1570         // set mCardStrings and the defaultEuiccCardId using the now available EID
1571         String eid = card.getEid();
1572         addCardId(eid);
1573         if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
1574                 || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1575             if (!mUiccSlots[slotId].isRemovable()) {
1576                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1577                 logWithLocalLog("onEidReady: eid="
1578                         + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1579                         + " slot=" + slotId + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1580             } else if (!mHasActiveBuiltInEuicc) {
1581                 // we only set a removable eUICC to the default if there are no active non-removable
1582                 // eUICCs
1583                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1584                 logWithLocalLog("onEidReady: eid="
1585                         + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1586                         + " from removable eUICC in slot=" + slotId + " mDefaultEuiccCardId="
1587                         + mDefaultEuiccCardId);
1588             }
1589         }
1590         card.unregisterForEidReady(this);
1591     }
1592 
1593     // Return true if the device has at least one built in eUICC based on the resource overlay
hasBuiltInEuicc()1594     private boolean hasBuiltInEuicc() {
1595         return mEuiccSlots != null &&  mEuiccSlots.length > 0;
1596     }
1597 
isBuiltInEuiccSlot(int slotIndex)1598     private boolean isBuiltInEuiccSlot(int slotIndex) {
1599         if (!mHasBuiltInEuicc) {
1600             return false;
1601         }
1602         for (int slot : mEuiccSlots) {
1603             if (slot == slotIndex) {
1604                 return true;
1605             }
1606         }
1607         return false;
1608     }
1609 
1610     /**
1611      * static method to return whether CDMA is supported on the device
1612      * @param context object representative of the application that is calling this method
1613      * @return true if CDMA is supported by the device
1614      */
isCdmaSupported(Context context)1615     public static boolean isCdmaSupported(Context context) {
1616         PackageManager packageManager = context.getPackageManager();
1617         boolean isCdmaSupported =
1618                 packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
1619         return isCdmaSupported;
1620     }
1621 
isValidPhoneIndex(int index)1622     private boolean isValidPhoneIndex(int index) {
1623         return (index >= 0 && index < TelephonyManager.getDefault().getPhoneCount());
1624     }
1625 
isValidSlotIndex(int index)1626     private boolean isValidSlotIndex(int index) {
1627         return (index >= 0 && index < mUiccSlots.length);
1628     }
1629 
isShuttingDown()1630     private boolean isShuttingDown() {
1631         for (int i = 0; i < TelephonyManager.getDefault().getActiveModemCount(); i++) {
1632             if (PhoneFactory.getPhone(i) != null &&
1633                     PhoneFactory.getPhone(i).isShuttingDown()) {
1634                 return true;
1635             }
1636         }
1637         return false;
1638     }
1639 
iccidMatches(String mvnoData, String iccId)1640     private static boolean iccidMatches(String mvnoData, String iccId) {
1641         String[] mvnoIccidList = mvnoData.split(",");
1642         for (String mvnoIccid : mvnoIccidList) {
1643             if (iccId.startsWith(mvnoIccid)) {
1644                 Log.d(LOG_TAG, "mvno icc id match found");
1645                 return true;
1646             }
1647         }
1648         return false;
1649     }
1650 
imsiMatches(String imsiDB, String imsiSIM)1651     private static boolean imsiMatches(String imsiDB, String imsiSIM) {
1652         // Note: imsiDB value has digit number or 'x' character for separating USIM information
1653         // for MVNO operator. And then digit number is matched at same order and 'x' character
1654         // could replace by any digit number.
1655         // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator,
1656         //     that means first 6 digits, 8th and 9th digit
1657         //     should be set in USIM for GG Operator.
1658         int len = imsiDB.length();
1659 
1660         if (len <= 0) return false;
1661         if (len > imsiSIM.length()) return false;
1662 
1663         for (int idx = 0; idx < len; idx++) {
1664             char c = imsiDB.charAt(idx);
1665             if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) {
1666                 continue;
1667             } else {
1668                 return false;
1669             }
1670         }
1671         return true;
1672     }
1673 
1674     /**
1675      * Check if MVNO type and data match IccRecords.
1676      *
1677      * @param slotIndex SIM slot index.
1678      * @param mvnoType the MVNO type
1679      * @param mvnoMatchData the MVNO match data
1680      * @return {@code true} if MVNO type and data match IccRecords, {@code false} otherwise.
1681      */
mvnoMatches(int slotIndex, int mvnoType, String mvnoMatchData)1682     public boolean mvnoMatches(int slotIndex, int mvnoType, String mvnoMatchData) {
1683         IccRecords iccRecords = getIccRecords(slotIndex, UiccController.APP_FAM_3GPP);
1684         if (iccRecords == null) {
1685             Log.d(LOG_TAG, "isMvnoMatched# IccRecords is null");
1686             return false;
1687         }
1688         if (mvnoType == ApnSetting.MVNO_TYPE_SPN) {
1689             String spn = iccRecords.getServiceProviderNameWithBrandOverride();
1690             if ((spn != null) && spn.equalsIgnoreCase(mvnoMatchData)) {
1691                 return true;
1692             }
1693         } else if (mvnoType == ApnSetting.MVNO_TYPE_IMSI) {
1694             String imsiSIM = iccRecords.getIMSI();
1695             if ((imsiSIM != null) && imsiMatches(mvnoMatchData, imsiSIM)) {
1696                 return true;
1697             }
1698         } else if (mvnoType == ApnSetting.MVNO_TYPE_GID) {
1699             String gid1 = iccRecords.getGid1();
1700             int mvno_match_data_length = mvnoMatchData.length();
1701             if ((gid1 != null) && (gid1.length() >= mvno_match_data_length)
1702                     && gid1.substring(0, mvno_match_data_length).equalsIgnoreCase(mvnoMatchData)) {
1703                 return true;
1704             }
1705         } else if (mvnoType == ApnSetting.MVNO_TYPE_ICCID) {
1706             String iccId = iccRecords.getIccId();
1707             if ((iccId != null) && iccidMatches(mvnoMatchData, iccId)) {
1708                 return true;
1709             }
1710         }
1711 
1712         return false;
1713     }
1714 
1715     /**
1716      * Set removable eSIM as default.
1717      * This API is added for test purpose to set removable eSIM as default eUICC.
1718      * @param isDefault Flag to set removable eSIM as default or not.
1719      */
setRemovableEsimAsDefaultEuicc(boolean isDefault)1720     public void setRemovableEsimAsDefaultEuicc(boolean isDefault) {
1721         mUseRemovableEsimAsDefault = isDefault;
1722         SharedPreferences.Editor editor =
1723                 PreferenceManager.getDefaultSharedPreferences(mContext).edit();
1724         editor.putBoolean(REMOVABLE_ESIM_AS_DEFAULT, isDefault);
1725         editor.apply();
1726         Rlog.d(LOG_TAG, "setRemovableEsimAsDefaultEuicc isDefault: " + isDefault);
1727     }
1728 
1729     /**
1730      * Returns whether the removable eSIM is default eUICC or not.
1731      * This API is added for test purpose to check whether removable eSIM is default eUICC or not.
1732      */
isRemovableEsimDefaultEuicc()1733     public boolean isRemovableEsimDefaultEuicc() {
1734         Rlog.d(LOG_TAG, "mUseRemovableEsimAsDefault: " + mUseRemovableEsimAsDefault);
1735         return mUseRemovableEsimAsDefault;
1736     }
1737 
1738     /**
1739      * Returns the MEP mode supported by the UiccSlot associated with slotIndex.
1740      * @param slotIndex physical slot index
1741      * @return MultipleEnabledProfilesMode supported by the slot
1742      */
getSupportedMepMode(int slotIndex)1743     public IccSlotStatus.MultipleEnabledProfilesMode getSupportedMepMode(int slotIndex) {
1744         synchronized (mLock) {
1745             UiccSlot slot = getUiccSlot(slotIndex);
1746             return slot != null ? slot.getSupportedMepMode()
1747                     : IccSlotStatus.MultipleEnabledProfilesMode.NONE;
1748         }
1749     }
1750 
1751     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
log(String string)1752     private void log(String string) {
1753         Rlog.d(LOG_TAG, string);
1754     }
1755 
logWithLocalLog(String string)1756     private void logWithLocalLog(String string) {
1757         Rlog.d(LOG_TAG, string);
1758         sLocalLog.log("UiccController: " + string);
1759     }
1760 
logeWithLocalLog(String string)1761     private void logeWithLocalLog(String string) {
1762         Rlog.e(LOG_TAG, string);
1763         sLocalLog.log("UiccController: " + string);
1764     }
1765 
1766     /** The supplied log should also indicate the caller to avoid ambiguity. */
addLocalLog(String data)1767     public static void addLocalLog(String data) {
1768         sLocalLog.log(data);
1769     }
1770 
getPrintableCardStrings()1771     private List<String> getPrintableCardStrings() {
1772         if (!ArrayUtils.isEmpty(mCardStrings)) {
1773             return mCardStrings.stream().map(SubscriptionInfo::getPrintableId).collect(
1774                     Collectors.toList());
1775         }
1776         return mCardStrings;
1777     }
1778 
dump(FileDescriptor fd, PrintWriter printWriter, String[] args)1779     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
1780         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
1781         pw.println("mIsCdmaSupported=" + isCdmaSupported(mContext));
1782         pw.println("mHasBuiltInEuicc=" + mHasBuiltInEuicc);
1783         pw.println("mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc);
1784         pw.println("mCardStrings=" + getPrintableCardStrings());
1785         pw.println("mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1786         pw.println("mPhoneIdToSlotId=" + Arrays.toString(mPhoneIdToSlotId));
1787         pw.println("mUseRemovableEsimAsDefault=" + mUseRemovableEsimAsDefault);
1788         pw.println("mUiccSlots: size=" + mUiccSlots.length);
1789         pw.increaseIndent();
1790         for (int i = 0; i < mUiccSlots.length; i++) {
1791             if (mUiccSlots[i] == null) {
1792                 pw.println("mUiccSlots[" + i + "]=null");
1793             } else {
1794                 pw.println("mUiccSlots[" + i + "]:");
1795                 pw.increaseIndent();
1796                 mUiccSlots[i].dump(fd, pw, args);
1797                 pw.decreaseIndent();
1798             }
1799         }
1800         pw.decreaseIndent();
1801         pw.println();
1802         mCarrierServiceBindHelper.dump(fd, pw, args);
1803         pw.println();
1804         pw.println("sLocalLog= ");
1805         pw.increaseIndent();
1806         mPinStorage.dump(fd, pw, args);
1807         sLocalLog.dump(fd, pw, args);
1808     }
1809 }
1810