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