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