• 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.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                     mCis[phoneId].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE,
601                             phoneId));
602                     // slot status should be the same on all RILs; request it only for phoneId 0
603                     if (phoneId == 0) {
604                         if (DBG) {
605                             log("Received EVENT_RADIO_AVAILABLE/EVENT_RADIO_ON for phoneId 0, "
606                                     + "calling getIccSlotsStatus");
607                         }
608                         mRadioConfig.getSimSlotsStatus(obtainMessage(EVENT_GET_SLOT_STATUS_DONE,
609                                 phoneId));
610                     }
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             if (slot != null) {
808                 intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId));
809             }
810             Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED "
811                     + TelephonyManager.simStateToString(state) + " for phone: " + phoneId
812                     + " slot: " + slotId + " port: " + slot.getPortIndexFromPhoneId(phoneId));
813             mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
814             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
815         }
816     }
817 
818     /**
819      * Broadcast SIM application state changed event.
820      *
821      * @param phoneId The phone id.
822      * @param state The SIM application state.
823      */
broadcastSimApplicationStateChanged(int phoneId, @SimState int state)824     private void broadcastSimApplicationStateChanged(int phoneId, @SimState int state) {
825         // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY,
826         // because that's the initial state and a broadcast should be sent only on a transition
827         // after SIM is PRESENT. The only exception is eSIM boot profile, where NOT_READY is the
828         // terminal state.
829         boolean isUnknownToNotReady =
830                 (mSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN
831                         && state == TelephonyManager.SIM_STATE_NOT_READY);
832         IccCard iccCard = PhoneFactory.getPhone(phoneId).getIccCard();
833         boolean emptyProfile = iccCard != null && iccCard.isEmptyProfile();
834         if (state != mSimApplicationState[phoneId] && (!isUnknownToNotReady || emptyProfile)) {
835             mSimApplicationState[phoneId] = state;
836             Intent intent = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
837             intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
838             intent.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
839             SubscriptionManager.putPhoneIdAndSubIdExtra(intent, phoneId);
840             // TODO(b/130664115) we populate this intent with the actual slotId. In the future we
841             // should do a review of whether to make this public
842             UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(phoneId);
843             int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId);
844             intent.putExtra(PhoneConstants.SLOT_KEY, slotId);
845             if (slot != null) {
846                 intent.putExtra(PhoneConstants.PORT_KEY, slot.getPortIndexFromPhoneId(phoneId));
847             }
848             Rlog.d(LOG_TAG, "Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED "
849                     + TelephonyManager.simStateToString(state)
850                     + " for phone: " + phoneId + " slot: " + slotId + "port: "
851                     + slot.getPortIndexFromPhoneId(phoneId));
852             mContext.sendBroadcast(intent, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
853             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
854         }
855     }
856 
857     /**
858      * Get SIM state from SIM lock reason.
859      *
860      * @param lockedReason The SIM lock reason.
861      *
862      * @return The SIM state.
863      */
864     @SimState
getSimStateFromLockedReason(String lockedReason)865     private static int getSimStateFromLockedReason(String lockedReason) {
866         switch (lockedReason) {
867             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN:
868                 return TelephonyManager.SIM_STATE_PIN_REQUIRED;
869             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK:
870                 return TelephonyManager.SIM_STATE_PUK_REQUIRED;
871             case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK:
872                 return TelephonyManager.SIM_STATE_NETWORK_LOCKED;
873             case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED:
874                 return TelephonyManager.SIM_STATE_PERM_DISABLED;
875             default:
876                 Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason);
877                 return TelephonyManager.SIM_STATE_UNKNOWN;
878         }
879     }
880 
881     /**
882      * Broadcast SIM state events.
883      *
884      * @param phoneId The phone id.
885      * @param simState The SIM state.
886      * @param reason SIM state changed reason.
887      */
broadcastSimStateEvents(int phoneId, IccCardConstants.State simState, @Nullable String reason)888     private void broadcastSimStateEvents(int phoneId, IccCardConstants.State simState,
889             @Nullable String reason) {
890         String legacyStringSimState = getIccStateIntentString(simState);
891         int cardState = TelephonyManager.SIM_STATE_UNKNOWN;
892         int applicationState = TelephonyManager.SIM_STATE_UNKNOWN;
893 
894         switch (simState) {
895             case ABSENT:
896                 cardState = TelephonyManager.SIM_STATE_ABSENT;
897                 break;
898             case PIN_REQUIRED:
899             case PUK_REQUIRED:
900             case NETWORK_LOCKED:
901             case PERM_DISABLED:
902                 cardState = TelephonyManager.SIM_STATE_PRESENT;
903                 applicationState = getSimStateFromLockedReason(reason);
904                 break;
905             case READY:
906             case NOT_READY:
907                 // Both READY and NOT_READY have the same card state and application state.
908                 cardState = TelephonyManager.SIM_STATE_PRESENT;
909                 applicationState = TelephonyManager.SIM_STATE_NOT_READY;
910                 break;
911             case CARD_IO_ERROR:
912                 cardState = TelephonyManager.SIM_STATE_CARD_IO_ERROR;
913                 applicationState = TelephonyManager.SIM_STATE_NOT_READY;
914                 break;
915             case CARD_RESTRICTED:
916                 cardState = TelephonyManager.SIM_STATE_CARD_RESTRICTED;
917                 applicationState = TelephonyManager.SIM_STATE_NOT_READY;
918                 break;
919             case LOADED:
920                 cardState = TelephonyManager.SIM_STATE_PRESENT;
921                 applicationState = TelephonyManager.SIM_STATE_LOADED;
922                 break;
923             case UNKNOWN:
924             default:
925                 break;
926         }
927 
928         broadcastSimStateChanged(phoneId, legacyStringSimState, reason);
929         broadcastSimCardStateChanged(phoneId, cardState);
930         broadcastSimApplicationStateChanged(phoneId, applicationState);
931     }
932 
933     /**
934      * Update carrier service.
935      *
936      * @param phoneId The phone id.
937      * @param simState The SIM state.
938      */
updateCarrierServices(int phoneId, @NonNull String simState)939     private void updateCarrierServices(int phoneId, @NonNull String simState) {
940         CarrierConfigManager configManager = mContext.getSystemService(CarrierConfigManager.class);
941         if (configManager != null) {
942             configManager.updateConfigForPhoneId(phoneId, simState);
943         }
944         mCarrierServiceBindHelper.updateForPhoneId(phoneId, simState);
945     }
946 
947     /**
948      * Update the SIM state.
949      *
950      * @param phoneId Phone id.
951      * @param state SIM state (legacy).
952      * @param reason The reason for SIM state update.
953      */
updateSimState(int phoneId, @NonNull IccCardConstants.State state, @Nullable String reason)954     public void updateSimState(int phoneId, @NonNull IccCardConstants.State state,
955             @Nullable String reason) {
956         post(() -> {
957             log("updateSimState: phoneId=" + phoneId + ", state=" + state + ", reason="
958                     + reason);
959             if (!SubscriptionManager.isValidPhoneId(phoneId)) {
960                 Rlog.e(LOG_TAG, "updateSimState: Invalid phone id " + phoneId);
961                 return;
962             }
963 
964             mTelephonyManager.setSimStateForPhone(phoneId, state.toString());
965 
966             String legacySimState = getIccStateIntentString(state);
967             int simState = state.ordinal();
968             SubscriptionManagerService.getInstance().updateSimState(phoneId, simState,
969                     this::post,
970                     () -> {
971                         // The following are executed after subscription update completed in
972                         // subscription manager service.
973 
974                         broadcastSimStateEvents(phoneId, state, reason);
975 
976                         UiccProfile uiccProfile = getUiccProfileForPhone(phoneId);
977 
978                         if (simState == TelephonyManager.SIM_STATE_READY) {
979                             // SIM_STATE_READY is not a final state.
980                             return;
981                         }
982 
983                         if (simState == TelephonyManager.SIM_STATE_NOT_READY
984                                 && (uiccProfile != null && !uiccProfile.isEmptyProfile())
985                                 && SubscriptionManagerService.getInstance()
986                                 .areUiccAppsEnabledOnCard(phoneId)) {
987                             // STATE_NOT_READY is not a final state for when both
988                             // 1) It's not an empty profile, and
989                             // 2) Its uicc applications are set to enabled.
990                             //
991                             // At this phase, we consider STATE_NOT_READY not a final state, so
992                             // return for now.
993                             log("updateSimState: SIM_STATE_NOT_READY is not a final "
994                                     + "state.");
995                             return;
996                         }
997 
998                         // At this point, the SIM state must be a final state (meaning we won't
999                         // get more SIM state updates). So resolve the carrier id and update the
1000                         // carrier services.
1001                         log("updateSimState: resolve carrier id and update carrier "
1002                                 + "services.");
1003                         PhoneFactory.getPhone(phoneId).resolveSubscriptionCarrierId(
1004                                 legacySimState);
1005                         updateCarrierServices(phoneId, legacySimState);
1006                     }
1007             );
1008         });
1009     }
1010 
onGetIccCardStatusDone(AsyncResult ar, Integer index)1011     private synchronized void onGetIccCardStatusDone(AsyncResult ar, Integer index) {
1012         if (ar.exception != null) {
1013             Rlog.e(LOG_TAG,"Error getting ICC status. "
1014                     + "RIL_REQUEST_GET_ICC_STATUS should "
1015                     + "never return an error", ar.exception);
1016             return;
1017         }
1018         if (!isValidPhoneIndex(index)) {
1019             Rlog.e(LOG_TAG,"onGetIccCardStatusDone: invalid index : " + index);
1020             return;
1021         }
1022         if (isShuttingDown()) {
1023             // Do not process the SIM/SLOT events during device shutdown,
1024             // as it may unnecessarily modify the persistent information
1025             // like, SubscriptionManager.UICC_APPLICATIONS_ENABLED.
1026             log("onGetIccCardStatusDone: shudown in progress ignore event");
1027             return;
1028         }
1029 
1030         IccCardStatus status = (IccCardStatus)ar.result;
1031 
1032         logWithLocalLog("onGetIccCardStatusDone: phoneId-" + index + " IccCardStatus: " + status);
1033 
1034         int slotId = status.mSlotPortMapping.mPhysicalSlotIndex;
1035         if (VDBG) log("onGetIccCardStatusDone: phoneId-" + index + " physicalSlotIndex " + slotId);
1036         if (slotId == INVALID_SLOT_ID) {
1037             slotId = index;
1038         }
1039 
1040         if (!mCis[0].supportsEid()) {
1041             // we will never get EID from the HAL, so set mDefaultEuiccCardId to UNSUPPORTED_CARD_ID
1042             if (DBG) log("eid is not supported");
1043             mDefaultEuiccCardId = UNSUPPORTED_CARD_ID;
1044         }
1045         mPhoneIdToSlotId[index] = slotId;
1046 
1047         if (VDBG) logPhoneIdToSlotIdMapping();
1048 
1049         if (mUiccSlots[slotId] == null) {
1050             if (VDBG) {
1051                 log("Creating mUiccSlots[" + slotId + "]; mUiccSlots.length = "
1052                         + mUiccSlots.length);
1053             }
1054             mUiccSlots[slotId] = new UiccSlot(mContext, true);
1055         }
1056 
1057         mUiccSlots[slotId].update(mCis[index], status, index, slotId);
1058 
1059         UiccCard card = mUiccSlots[slotId].getUiccCard();
1060         if (card == null) {
1061             if (DBG) log("mUiccSlots[" + slotId + "] has no card. Notifying IccChangedRegistrants");
1062             mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
1063             return;
1064         }
1065 
1066         UiccPort port = card.getUiccPort(status.mSlotPortMapping.mPortIndex);
1067         if (port == null) {
1068             if (DBG) log("mUiccSlots[" + slotId + "] has no UiccPort with index["
1069                     + status.mSlotPortMapping.mPortIndex + "]. Notifying IccChangedRegistrants");
1070             mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
1071             return;
1072         }
1073 
1074         String cardString = null;
1075         boolean isEuicc = mUiccSlots[slotId].isEuicc();
1076         if (isEuicc) {
1077             cardString = ((EuiccCard) card).getEid();
1078         } else {
1079             cardString = card.getUiccPort(status.mSlotPortMapping.mPortIndex).getIccId();
1080         }
1081 
1082         if (cardString != null) {
1083             addCardId(cardString);
1084         }
1085 
1086         // EID is unpopulated if Radio HAL < 1.4 (RadioConfig < 1.2)
1087         // If so, just register for EID loaded and skip this stuff
1088         if (isEuicc && mDefaultEuiccCardId != UNSUPPORTED_CARD_ID) {
1089             if (cardString == null) {
1090                 ((EuiccCard) card).registerForEidReady(this, EVENT_EID_READY, index);
1091             } else {
1092                 // If we know the EID from IccCardStatus, just use it to set mDefaultEuiccCardId if
1093                 // it's not already set.
1094                 // This is needed in cases where slot status doesn't include EID, and we don't want
1095                 // to register for EID from APDU because we already know cardString from a previous
1096                 // APDU
1097                 if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
1098                         || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1099                     mDefaultEuiccCardId = convertToPublicCardId(cardString);
1100                     logWithLocalLog("IccCardStatus eid="
1101                             + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, cardString) + " slot=" + slotId
1102                             + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1103                 }
1104             }
1105         }
1106 
1107         if (DBG) log("Notifying IccChangedRegistrants");
1108         mIccChangedRegistrants.notifyRegistrants(new AsyncResult(null, index, null));
1109     }
1110 
1111     /**
1112      * Add a cardString to mCardStrings. If this is an ICCID, trailing Fs will be automatically
1113      * stripped.
1114      */
addCardId(String cardString)1115     private void addCardId(String cardString) {
1116         if (TextUtils.isEmpty(cardString)) {
1117             return;
1118         }
1119         if (cardString.length() < EID_LENGTH) {
1120             cardString = IccUtils.stripTrailingFs(cardString);
1121         }
1122         if (!mCardStrings.contains(cardString)) {
1123             mCardStrings.add(cardString);
1124             saveCardStrings();
1125         }
1126     }
1127 
1128     /**
1129      * Converts an integer cardId (public card ID) to a card string.
1130      * @param cardId to convert
1131      * @return cardString, or null if the cardId is not valid
1132      */
convertToCardString(int cardId)1133     public String convertToCardString(int cardId) {
1134         if (cardId < 0 || cardId >= mCardStrings.size()) {
1135             log("convertToCardString: cardId " + cardId + " is not valid");
1136             return null;
1137         }
1138         return mCardStrings.get(cardId);
1139     }
1140 
1141     /**
1142      * Converts the card string (the ICCID/EID, formerly named card ID) to the public int cardId.
1143      * If the given cardString is an ICCID, trailing Fs will be automatically stripped before trying
1144      * to match to a card ID.
1145      *
1146      * @return the matching cardId, or UNINITIALIZED_CARD_ID if the card string does not map to a
1147      * currently loaded cardId, or UNSUPPORTED_CARD_ID if the device does not support card IDs
1148      */
convertToPublicCardId(String cardString)1149     public int convertToPublicCardId(String cardString) {
1150         if (mDefaultEuiccCardId == UNSUPPORTED_CARD_ID) {
1151             // even if cardString is not an EID, if EID is not supported (e.g. HAL < 1.2) we can't
1152             // guarentee a working card ID implementation, so return UNSUPPORTED_CARD_ID
1153             return UNSUPPORTED_CARD_ID;
1154         }
1155         if (TextUtils.isEmpty(cardString)) {
1156             return UNINITIALIZED_CARD_ID;
1157         }
1158 
1159         if (cardString.length() < EID_LENGTH) {
1160             cardString = IccUtils.stripTrailingFs(cardString);
1161         }
1162         int id = mCardStrings.indexOf(cardString);
1163         if (id == -1) {
1164             return UNINITIALIZED_CARD_ID;
1165         } else {
1166             return id;
1167         }
1168     }
1169 
1170     /**
1171      * Returns the UiccCardInfo of all currently inserted UICCs and embedded eUICCs.
1172      */
getAllUiccCardInfos()1173     public ArrayList<UiccCardInfo> getAllUiccCardInfos() {
1174         synchronized (mLock) {
1175             ArrayList<UiccCardInfo> infos = new ArrayList<>();
1176             for (int slotIndex = 0; slotIndex < mUiccSlots.length; slotIndex++) {
1177                 final UiccSlot slot = mUiccSlots[slotIndex];
1178                 if (slot == null) continue;
1179                 boolean isEuicc = slot.isEuicc();
1180                 String eid = null;
1181                 UiccCard card = slot.getUiccCard();
1182                 int cardId = UNINITIALIZED_CARD_ID;
1183                 boolean isRemovable = slot.isRemovable();
1184 
1185                 // first we try to populate UiccCardInfo using the UiccCard, but if it doesn't exist
1186                 // (e.g. the slot is for an inactive eUICC) then we try using the UiccSlot.
1187                 if (card != null) {
1188                     if (isEuicc) {
1189                         eid = ((EuiccCard) card).getEid();
1190                         cardId = convertToPublicCardId(eid);
1191                     } else {
1192                         // In case of non Euicc, use default port index to get the IccId.
1193                         UiccPort port = card.getUiccPort(TelephonyManager.DEFAULT_PORT_INDEX);
1194                         if (port == null) {
1195                             AnomalyReporter.reportAnomaly(
1196                                     UUID.fromString("92885ba7-98bb-490a-ba19-987b1c8b2055"),
1197                                     "UiccController: Found UiccPort Null object.");
1198                         }
1199                         String iccId = (port != null) ? port.getIccId() : null;
1200                         cardId = convertToPublicCardId(iccId);
1201                     }
1202                 } else {
1203                     // This iccid is used for non Euicc only, so use default port index
1204                     String iccId = slot.getIccId(TelephonyManager.DEFAULT_PORT_INDEX);
1205                     // Fill in the fields we can
1206                     if (!isEuicc && !TextUtils.isEmpty(iccId)) {
1207                         cardId = convertToPublicCardId(iccId);
1208                     }
1209                 }
1210 
1211                 List<UiccPortInfo> portInfos = new ArrayList<>();
1212                 int[] portIndexes = slot.getPortList();
1213                 for (int portIdx : portIndexes) {
1214                     String iccId = IccUtils.stripTrailingFs(slot.getIccId(portIdx));
1215                     portInfos.add(new UiccPortInfo(iccId, portIdx,
1216                             slot.getPhoneIdFromPortIndex(portIdx), slot.isPortActive(portIdx)));
1217                 }
1218                 UiccCardInfo info = new UiccCardInfo(
1219                         isEuicc, cardId, eid, slotIndex, isRemovable,
1220                         slot.isMultipleEnabledProfileSupported(), portInfos);
1221                 infos.add(info);
1222             }
1223             return infos;
1224         }
1225     }
1226 
1227     /**
1228      * Get the card ID of the default eUICC.
1229      */
getCardIdForDefaultEuicc()1230     public int getCardIdForDefaultEuicc() {
1231         if (mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1232             return UNSUPPORTED_CARD_ID;
1233         }
1234         // To support removable eSIM to pass GCT/PTCRB test in DSDS mode, we should make sure all
1235         // the download/activation requests are by default route to the removable eSIM slot.
1236         // To satisfy above condition, we should return removable eSIM cardId as default.
1237         if (mUseRemovableEsimAsDefault && !TelephonyUtils.IS_USER) {
1238             for (UiccSlot slot : mUiccSlots) {
1239                 if (slot != null && slot.isRemovable() && slot.isEuicc() && slot.isActive()) {
1240                     int cardId = convertToPublicCardId(slot.getEid());
1241                     Rlog.d(LOG_TAG,
1242                             "getCardIdForDefaultEuicc: Removable eSIM is default, cardId: "
1243                                     + cardId);
1244                     return cardId;
1245                 }
1246             }
1247             Rlog.d(LOG_TAG, "getCardIdForDefaultEuicc: No removable eSIM slot is found");
1248         }
1249         return mDefaultEuiccCardId;
1250     }
1251 
1252     /** Get the {@link PinStorage}. */
getPinStorage()1253     public PinStorage getPinStorage() {
1254         return mPinStorage;
1255     }
1256 
loadCardStrings()1257     private ArrayList<String> loadCardStrings() {
1258         String cardStrings =
1259                 PreferenceManager.getDefaultSharedPreferences(mContext).getString(CARD_STRINGS, "");
1260         if (TextUtils.isEmpty(cardStrings)) {
1261             // just return an empty list, since String.split would return the list { "" }
1262             return new ArrayList<String>();
1263         }
1264         return new ArrayList<String>(Arrays.asList(cardStrings.split(",")));
1265     }
1266 
saveCardStrings()1267     private void saveCardStrings() {
1268         SharedPreferences.Editor editor =
1269                 PreferenceManager.getDefaultSharedPreferences(mContext).edit();
1270         editor.putString(CARD_STRINGS, TextUtils.join(",", mCardStrings));
1271         editor.commit();
1272     }
1273 
onGetSlotStatusDone(AsyncResult ar)1274     private synchronized void onGetSlotStatusDone(AsyncResult ar) {
1275         if (!mIsSlotStatusSupported) {
1276             if (VDBG) log("onGetSlotStatusDone: ignoring since mIsSlotStatusSupported is false");
1277             return;
1278         }
1279         Throwable e = ar.exception;
1280         if (e != null) {
1281             if (!(e instanceof CommandException) || ((CommandException) e).getCommandError()
1282                     != CommandException.Error.REQUEST_NOT_SUPPORTED) {
1283                 // this is not expected; there should be no exception other than
1284                 // REQUEST_NOT_SUPPORTED
1285                 logeWithLocalLog("Unexpected error getting slot status: " + ar.exception);
1286             } else {
1287                 // REQUEST_NOT_SUPPORTED
1288                 logWithLocalLog("onGetSlotStatusDone: request not supported; marking "
1289                         + "mIsSlotStatusSupported to false");
1290                 mIsSlotStatusSupported = false;
1291             }
1292             return;
1293         }
1294         if (isShuttingDown()) {
1295             // Do not process the SIM/SLOT events during device shutdown,
1296             // as it may unnecessarily modify the persistent information
1297             // like, SubscriptionManager.UICC_APPLICATIONS_ENABLED.
1298             log("onGetSlotStatusDone: shudown in progress ignore event");
1299             return;
1300         }
1301 
1302         ArrayList<IccSlotStatus> status = (ArrayList<IccSlotStatus>) ar.result;
1303 
1304         if (!slotStatusChanged(status)) {
1305             log("onGetSlotStatusDone: No change in slot status");
1306             return;
1307         }
1308         logWithLocalLog("onGetSlotStatusDone: " + status);
1309 
1310         sLastSlotStatus = status;
1311 
1312         int numActivePorts = 0;
1313         boolean isDefaultEuiccCardIdSet = false;
1314         boolean anyEuiccIsActive = false;
1315         mHasActiveBuiltInEuicc = false;
1316 
1317         int numSlots = status.size();
1318         if (mUiccSlots.length < numSlots) {
1319             logeWithLocalLog("The number of the physical slots reported " + numSlots
1320                     + " is greater than the expectation " + mUiccSlots.length);
1321             numSlots = mUiccSlots.length;
1322         }
1323 
1324         for (int i = 0; i < numSlots; i++) {
1325             IccSlotStatus iss = status.get(i);
1326             boolean isActive = hasActivePort(iss.mSimPortInfos);
1327             if (mUiccSlots[i] == null) {
1328                 if (VDBG) {
1329                     log("Creating mUiccSlot[" + i + "]; mUiccSlots.length = " + mUiccSlots.length);
1330                 }
1331                 mUiccSlots[i] = new UiccSlot(mContext, isActive);
1332             }
1333 
1334             if (isActive) { // check isActive flag so that we don't have to iterate through all
1335                 for (int j = 0; j < iss.mSimPortInfos.length; j++) {
1336                     if (iss.mSimPortInfos[j].mPortActive) {
1337                         int logicalSlotIndex = iss.mSimPortInfos[j].mLogicalSlotIndex;
1338                         // Correctness check: logicalSlotIndex should be valid for an active slot
1339                         if (!isValidPhoneIndex(logicalSlotIndex)) {
1340                             Rlog.e(LOG_TAG, "Skipping slot " + i + " portIndex " + j + " as phone "
1341                                     + logicalSlotIndex
1342                                     + " is not available to communicate with this slot");
1343                         } else {
1344                             mPhoneIdToSlotId[logicalSlotIndex] = i;
1345                         }
1346                         numActivePorts++;
1347                     }
1348                 }
1349             }
1350 
1351             mUiccSlots[i].update(mCis, iss, i);
1352 
1353             if (mUiccSlots[i].isEuicc()) {
1354                 if (isActive) {
1355                     anyEuiccIsActive = true;
1356 
1357                     if (isBuiltInEuiccSlot(i)) {
1358                         mHasActiveBuiltInEuicc = true;
1359                     }
1360                 }
1361                 String eid = iss.eid;
1362                 if (TextUtils.isEmpty(eid)) {
1363                     // iss.eid is not populated on HAL<1.4
1364                     continue;
1365                 }
1366 
1367                 addCardId(eid);
1368 
1369                 // whenever slot status is received, set default card to the non-removable eUICC
1370                 // with the lowest slot index.
1371                 if (!mUiccSlots[i].isRemovable() && !isDefaultEuiccCardIdSet) {
1372                     isDefaultEuiccCardIdSet = true;
1373                     mDefaultEuiccCardId = convertToPublicCardId(eid);
1374                     logWithLocalLog("Using eid=" + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1375                             + " in slot=" + i + " to set mDefaultEuiccCardId="
1376                             + mDefaultEuiccCardId);
1377                 }
1378             }
1379         }
1380 
1381         if (!mHasActiveBuiltInEuicc && !isDefaultEuiccCardIdSet) {
1382             // if there are no active built-in eUICCs, then consider setting a removable eUICC to
1383             // the default.
1384             // Note that on HAL<1.2, it's possible that a built-in eUICC exists, but does not
1385             // correspond to any slot in mUiccSlots. This logic is still safe in that case because
1386             // SlotStatus is only for HAL >= 1.2
1387             for (int i = 0; i < numSlots; i++) {
1388                 if (mUiccSlots[i].isEuicc()) {
1389                     String eid = status.get(i).eid;
1390                     if (!TextUtils.isEmpty(eid)) {
1391                         isDefaultEuiccCardIdSet = true;
1392                         mDefaultEuiccCardId = convertToPublicCardId(eid);
1393                         logWithLocalLog("Using eid="
1394                                 + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1395                                 + " from removable eUICC in slot=" + i
1396                                 + " to set mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1397                         break;
1398                     }
1399                 }
1400             }
1401         }
1402 
1403         if (mHasBuiltInEuicc && !anyEuiccIsActive && !isDefaultEuiccCardIdSet) {
1404             logWithLocalLog(
1405                     "onGetSlotStatusDone: mDefaultEuiccCardId=TEMPORARILY_UNSUPPORTED_CARD_ID");
1406             isDefaultEuiccCardIdSet = true;
1407             mDefaultEuiccCardId = TEMPORARILY_UNSUPPORTED_CARD_ID;
1408         }
1409 
1410 
1411         if (!isDefaultEuiccCardIdSet) {
1412             if (mDefaultEuiccCardId >= 0) {
1413                 // if mDefaultEuiccCardId has already been set to an actual eUICC,
1414                 // don't overwrite mDefaultEuiccCardId unless that eUICC is no longer inserted
1415                 boolean defaultEuiccCardIdIsStillInserted = false;
1416                 String cardString = mCardStrings.get(mDefaultEuiccCardId);
1417                 for (UiccSlot slot : mUiccSlots) {
1418                     if (slot.getUiccCard() == null) {
1419                         continue;
1420                     }
1421                     if (cardString.equals(
1422                             IccUtils.stripTrailingFs(slot.getUiccCard().getCardId()))) {
1423                         defaultEuiccCardIdIsStillInserted = true;
1424                     }
1425                 }
1426                 if (!defaultEuiccCardIdIsStillInserted) {
1427                     logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId="
1428                             + mDefaultEuiccCardId
1429                             + " is no longer inserted. Setting mDefaultEuiccCardId=UNINITIALIZED");
1430                     mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1431                 }
1432             } else {
1433                 // no known eUICCs at all (it's possible that an eUICC is inserted and we just don't
1434                 // know it's EID)
1435                 logWithLocalLog("onGetSlotStatusDone: mDefaultEuiccCardId=UNINITIALIZED");
1436                 mDefaultEuiccCardId = UNINITIALIZED_CARD_ID;
1437             }
1438         }
1439 
1440         if (VDBG) logPhoneIdToSlotIdMapping();
1441 
1442         // Correctness check: number of active ports should be valid
1443         if (numActivePorts != mPhoneIdToSlotId.length) {
1444             Rlog.e(LOG_TAG, "Number of active ports " + numActivePorts
1445                        + " does not match the number of Phones" + mPhoneIdToSlotId.length);
1446         }
1447 
1448         // broadcast slot status changed
1449         final BroadcastOptions options = BroadcastOptions.makeBasic();
1450         options.setBackgroundActivityStartsAllowed(true);
1451         Intent intent = new Intent(TelephonyManager.ACTION_SIM_SLOT_STATUS_CHANGED);
1452         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1453         mContext.sendBroadcast(intent, android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
1454                 options.toBundle());
1455     }
1456 
hasActivePort(IccSimPortInfo[] simPortInfos)1457     private boolean hasActivePort(IccSimPortInfo[] simPortInfos) {
1458         for (IccSimPortInfo simPortInfo : simPortInfos) {
1459             if (simPortInfo.mPortActive) {
1460                 return true;
1461             }
1462         }
1463         return false;
1464     }
1465 
1466     /**
1467      * Check if slot status has changed from the last received one
1468      */
1469     @VisibleForTesting
slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList)1470     public boolean slotStatusChanged(ArrayList<IccSlotStatus> slotStatusList) {
1471         if (sLastSlotStatus == null || sLastSlotStatus.size() != slotStatusList.size()) {
1472             return true;
1473         }
1474         for (int i = 0; i < slotStatusList.size(); i++) {
1475             if (!sLastSlotStatus.get(i).equals(slotStatusList.get(i))) {
1476                 return true;
1477             }
1478         }
1479         return false;
1480     }
1481 
logPhoneIdToSlotIdMapping()1482     private void logPhoneIdToSlotIdMapping() {
1483         log("mPhoneIdToSlotId mapping:");
1484         for (int i = 0; i < mPhoneIdToSlotId.length; i++) {
1485             log("    phoneId " + i + " slotId " + mPhoneIdToSlotId[i]);
1486         }
1487     }
1488 
onSimRefresh(AsyncResult ar, Integer index)1489     private void onSimRefresh(AsyncResult ar, Integer index) {
1490         if (ar.exception != null) {
1491             Rlog.e(LOG_TAG, "onSimRefresh: Sim REFRESH with exception: " + ar.exception);
1492             return;
1493         }
1494 
1495         if (!isValidPhoneIndex(index)) {
1496             Rlog.e(LOG_TAG,"onSimRefresh: invalid index : " + index);
1497             return;
1498         }
1499 
1500         IccRefreshResponse resp = (IccRefreshResponse) ar.result;
1501         logWithLocalLog("onSimRefresh: index " + index + ", " + resp);
1502 
1503         if (resp == null) {
1504             Rlog.e(LOG_TAG, "onSimRefresh: received without input");
1505             return;
1506         }
1507 
1508         UiccCard uiccCard = getUiccCardForPhone(index);
1509         if (uiccCard == null) {
1510             Rlog.e(LOG_TAG,"onSimRefresh: refresh on null card : " + index);
1511             return;
1512         }
1513 
1514         UiccPort uiccPort = getUiccPortForPhone(index);
1515         if (uiccPort == null) {
1516             Rlog.e(LOG_TAG, "onSimRefresh: refresh on null port : " + index);
1517             return;
1518         }
1519 
1520         boolean changed = false;
1521         switch(resp.refreshResult) {
1522             // Reset the required apps when we know about the refresh so that
1523             // anyone interested does not get stale state.
1524             case IccRefreshResponse.REFRESH_RESULT_RESET:
1525                 changed = uiccPort.resetAppWithAid(resp.aid, true /* reset */);
1526                 break;
1527             case IccRefreshResponse.REFRESH_RESULT_INIT:
1528                 // don't dispose CatService on SIM REFRESH of type INIT
1529                 changed = uiccPort.resetAppWithAid(resp.aid, false /* initialize */);
1530                 break;
1531             default:
1532                 return;
1533         }
1534 
1535         if (changed && resp.refreshResult == IccRefreshResponse.REFRESH_RESULT_RESET) {
1536             // If there is any change on RESET, reset carrier config as well. From carrier config
1537             // perspective, this is treated the same as sim state unknown
1538             CarrierConfigManager configManager = (CarrierConfigManager)
1539                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1540             configManager.updateConfigForPhoneId(index, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
1541         }
1542 
1543         // The card status could have changed. Get the latest state.
1544         mCis[index].getIccCardStatus(obtainMessage(EVENT_GET_ICC_STATUS_DONE, index));
1545     }
1546 
1547     // for HAL 1.2-1.3 we register for EID ready, set mCardStrings and mDefaultEuiccCardId here.
1548     // Note that if there are multiple eUICCs on HAL 1.2-1.3, the default eUICC is the one whose EID
1549     // is first loaded
onEidReady(AsyncResult ar, Integer index)1550     private void onEidReady(AsyncResult ar, Integer index) {
1551         if (ar.exception != null) {
1552             Rlog.e(LOG_TAG, "onEidReady: exception: " + ar.exception);
1553             return;
1554         }
1555 
1556         if (!isValidPhoneIndex(index)) {
1557             Rlog.e(LOG_TAG, "onEidReady: invalid index: " + index);
1558             return;
1559         }
1560         int slotId = mPhoneIdToSlotId[index];
1561         EuiccCard card = (EuiccCard) mUiccSlots[slotId].getUiccCard();
1562         if (card == null) {
1563             Rlog.e(LOG_TAG, "onEidReady: UiccCard in slot " + slotId + " is null");
1564             return;
1565         }
1566 
1567         // set mCardStrings and the defaultEuiccCardId using the now available EID
1568         String eid = card.getEid();
1569         addCardId(eid);
1570         if (mDefaultEuiccCardId == UNINITIALIZED_CARD_ID
1571                 || mDefaultEuiccCardId == TEMPORARILY_UNSUPPORTED_CARD_ID) {
1572             if (!mUiccSlots[slotId].isRemovable()) {
1573                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1574                 logWithLocalLog("onEidReady: eid="
1575                         + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1576                         + " slot=" + slotId + " mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1577             } else if (!mHasActiveBuiltInEuicc) {
1578                 // we only set a removable eUICC to the default if there are no active non-removable
1579                 // eUICCs
1580                 mDefaultEuiccCardId = convertToPublicCardId(eid);
1581                 logWithLocalLog("onEidReady: eid="
1582                         + Rlog.pii(TelephonyUtils.IS_DEBUGGABLE, eid)
1583                         + " from removable eUICC in slot=" + slotId + " mDefaultEuiccCardId="
1584                         + mDefaultEuiccCardId);
1585             }
1586         }
1587         card.unregisterForEidReady(this);
1588     }
1589 
1590     // Return true if the device has at least one built in eUICC based on the resource overlay
hasBuiltInEuicc()1591     private boolean hasBuiltInEuicc() {
1592         return mEuiccSlots != null &&  mEuiccSlots.length > 0;
1593     }
1594 
isBuiltInEuiccSlot(int slotIndex)1595     private boolean isBuiltInEuiccSlot(int slotIndex) {
1596         if (!mHasBuiltInEuicc) {
1597             return false;
1598         }
1599         for (int slot : mEuiccSlots) {
1600             if (slot == slotIndex) {
1601                 return true;
1602             }
1603         }
1604         return false;
1605     }
1606 
1607     /**
1608      * static method to return whether CDMA is supported on the device
1609      * @param context object representative of the application that is calling this method
1610      * @return true if CDMA is supported by the device
1611      */
isCdmaSupported(Context context)1612     public static boolean isCdmaSupported(Context context) {
1613         PackageManager packageManager = context.getPackageManager();
1614         boolean isCdmaSupported =
1615                 packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
1616         return isCdmaSupported;
1617     }
1618 
isValidPhoneIndex(int index)1619     private boolean isValidPhoneIndex(int index) {
1620         return (index >= 0 && index < TelephonyManager.getDefault().getPhoneCount());
1621     }
1622 
isValidSlotIndex(int index)1623     private boolean isValidSlotIndex(int index) {
1624         return (index >= 0 && index < mUiccSlots.length);
1625     }
1626 
isShuttingDown()1627     private boolean isShuttingDown() {
1628         for (int i = 0; i < TelephonyManager.getDefault().getActiveModemCount(); i++) {
1629             if (PhoneFactory.getPhone(i) != null &&
1630                     PhoneFactory.getPhone(i).isShuttingDown()) {
1631                 return true;
1632             }
1633         }
1634         return false;
1635     }
1636 
iccidMatches(String mvnoData, String iccId)1637     private static boolean iccidMatches(String mvnoData, String iccId) {
1638         String[] mvnoIccidList = mvnoData.split(",");
1639         for (String mvnoIccid : mvnoIccidList) {
1640             if (iccId.startsWith(mvnoIccid)) {
1641                 Log.d(LOG_TAG, "mvno icc id match found");
1642                 return true;
1643             }
1644         }
1645         return false;
1646     }
1647 
imsiMatches(String imsiDB, String imsiSIM)1648     private static boolean imsiMatches(String imsiDB, String imsiSIM) {
1649         // Note: imsiDB value has digit number or 'x' character for separating USIM information
1650         // for MVNO operator. And then digit number is matched at same order and 'x' character
1651         // could replace by any digit number.
1652         // ex) if imsiDB inserted '310260x10xxxxxx' for GG Operator,
1653         //     that means first 6 digits, 8th and 9th digit
1654         //     should be set in USIM for GG Operator.
1655         int len = imsiDB.length();
1656 
1657         if (len <= 0) return false;
1658         if (len > imsiSIM.length()) return false;
1659 
1660         for (int idx = 0; idx < len; idx++) {
1661             char c = imsiDB.charAt(idx);
1662             if ((c == 'x') || (c == 'X') || (c == imsiSIM.charAt(idx))) {
1663                 continue;
1664             } else {
1665                 return false;
1666             }
1667         }
1668         return true;
1669     }
1670 
1671     /**
1672      * Check if MVNO type and data match IccRecords.
1673      *
1674      * @param slotIndex SIM slot index.
1675      * @param mvnoType the MVNO type
1676      * @param mvnoMatchData the MVNO match data
1677      * @return {@code true} if MVNO type and data match IccRecords, {@code false} otherwise.
1678      */
mvnoMatches(int slotIndex, int mvnoType, String mvnoMatchData)1679     public boolean mvnoMatches(int slotIndex, int mvnoType, String mvnoMatchData) {
1680         IccRecords iccRecords = getIccRecords(slotIndex, UiccController.APP_FAM_3GPP);
1681         if (iccRecords == null) {
1682             Log.d(LOG_TAG, "isMvnoMatched# IccRecords is null");
1683             return false;
1684         }
1685         if (mvnoType == ApnSetting.MVNO_TYPE_SPN) {
1686             String spn = iccRecords.getServiceProviderNameWithBrandOverride();
1687             if ((spn != null) && spn.equalsIgnoreCase(mvnoMatchData)) {
1688                 return true;
1689             }
1690         } else if (mvnoType == ApnSetting.MVNO_TYPE_IMSI) {
1691             String imsiSIM = iccRecords.getIMSI();
1692             if ((imsiSIM != null) && imsiMatches(mvnoMatchData, imsiSIM)) {
1693                 return true;
1694             }
1695         } else if (mvnoType == ApnSetting.MVNO_TYPE_GID) {
1696             String gid1 = iccRecords.getGid1();
1697             int mvno_match_data_length = mvnoMatchData.length();
1698             if ((gid1 != null) && (gid1.length() >= mvno_match_data_length)
1699                     && gid1.substring(0, mvno_match_data_length).equalsIgnoreCase(mvnoMatchData)) {
1700                 return true;
1701             }
1702         } else if (mvnoType == ApnSetting.MVNO_TYPE_ICCID) {
1703             String iccId = iccRecords.getIccId();
1704             if ((iccId != null) && iccidMatches(mvnoMatchData, iccId)) {
1705                 return true;
1706             }
1707         }
1708 
1709         return false;
1710     }
1711 
1712     /**
1713      * Set removable eSIM as default.
1714      * This API is added for test purpose to set removable eSIM as default eUICC.
1715      * @param isDefault Flag to set removable eSIM as default or not.
1716      */
setRemovableEsimAsDefaultEuicc(boolean isDefault)1717     public void setRemovableEsimAsDefaultEuicc(boolean isDefault) {
1718         mUseRemovableEsimAsDefault = isDefault;
1719         SharedPreferences.Editor editor =
1720                 PreferenceManager.getDefaultSharedPreferences(mContext).edit();
1721         editor.putBoolean(REMOVABLE_ESIM_AS_DEFAULT, isDefault);
1722         editor.apply();
1723         Rlog.d(LOG_TAG, "setRemovableEsimAsDefaultEuicc isDefault: " + isDefault);
1724     }
1725 
1726     /**
1727      * Returns whether the removable eSIM is default eUICC or not.
1728      * This API is added for test purpose to check whether removable eSIM is default eUICC or not.
1729      */
isRemovableEsimDefaultEuicc()1730     public boolean isRemovableEsimDefaultEuicc() {
1731         Rlog.d(LOG_TAG, "mUseRemovableEsimAsDefault: " + mUseRemovableEsimAsDefault);
1732         return mUseRemovableEsimAsDefault;
1733     }
1734 
1735     /**
1736      * Returns the MEP mode supported by the UiccSlot associated with slotIndex.
1737      * @param slotIndex physical slot index
1738      * @return MultipleEnabledProfilesMode supported by the slot
1739      */
getSupportedMepMode(int slotIndex)1740     public IccSlotStatus.MultipleEnabledProfilesMode getSupportedMepMode(int slotIndex) {
1741         synchronized (mLock) {
1742             UiccSlot slot = getUiccSlot(slotIndex);
1743             return slot != null ? slot.getSupportedMepMode()
1744                     : IccSlotStatus.MultipleEnabledProfilesMode.NONE;
1745         }
1746     }
1747 
1748     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
log(String string)1749     private void log(String string) {
1750         Rlog.d(LOG_TAG, string);
1751     }
1752 
logWithLocalLog(String string)1753     private void logWithLocalLog(String string) {
1754         Rlog.d(LOG_TAG, string);
1755         sLocalLog.log("UiccController: " + string);
1756     }
1757 
logeWithLocalLog(String string)1758     private void logeWithLocalLog(String string) {
1759         Rlog.e(LOG_TAG, string);
1760         sLocalLog.log("UiccController: " + string);
1761     }
1762 
1763     /** The supplied log should also indicate the caller to avoid ambiguity. */
addLocalLog(String data)1764     public static void addLocalLog(String data) {
1765         sLocalLog.log(data);
1766     }
1767 
getPrintableCardStrings()1768     private List<String> getPrintableCardStrings() {
1769         if (!ArrayUtils.isEmpty(mCardStrings)) {
1770             return mCardStrings.stream().map(SubscriptionInfo::getPrintableId).collect(
1771                     Collectors.toList());
1772         }
1773         return mCardStrings;
1774     }
1775 
dump(FileDescriptor fd, PrintWriter printWriter, String[] args)1776     public void dump(FileDescriptor fd, PrintWriter printWriter, String[] args) {
1777         IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, "  ");
1778         pw.println("mIsCdmaSupported=" + isCdmaSupported(mContext));
1779         pw.println("mHasBuiltInEuicc=" + mHasBuiltInEuicc);
1780         pw.println("mHasActiveBuiltInEuicc=" + mHasActiveBuiltInEuicc);
1781         pw.println("mCardStrings=" + getPrintableCardStrings());
1782         pw.println("mDefaultEuiccCardId=" + mDefaultEuiccCardId);
1783         pw.println("mPhoneIdToSlotId=" + Arrays.toString(mPhoneIdToSlotId));
1784         pw.println("mUseRemovableEsimAsDefault=" + mUseRemovableEsimAsDefault);
1785         pw.println("mUiccSlots: size=" + mUiccSlots.length);
1786         pw.increaseIndent();
1787         for (int i = 0; i < mUiccSlots.length; i++) {
1788             if (mUiccSlots[i] == null) {
1789                 pw.println("mUiccSlots[" + i + "]=null");
1790             } else {
1791                 pw.println("mUiccSlots[" + i + "]:");
1792                 pw.increaseIndent();
1793                 mUiccSlots[i].dump(fd, pw, args);
1794                 pw.decreaseIndent();
1795             }
1796         }
1797         pw.decreaseIndent();
1798         pw.println();
1799         pw.println("sLocalLog= ");
1800         pw.increaseIndent();
1801         mPinStorage.dump(fd, pw, args);
1802         sLocalLog.dump(fd, pw, args);
1803     }
1804 }
1805