• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 * Copyright (C) 2014 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;
18 
19 import android.Manifest;
20 import android.annotation.Nullable;
21 import android.annotation.UnsupportedAppUsage;
22 import android.app.ActivityManager;
23 import android.app.UserSwitchObserver;
24 import android.content.ContentResolver;
25 import android.content.ContentValues;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.SharedPreferences;
29 import android.content.pm.IPackageManager;
30 import android.os.AsyncResult;
31 import android.os.Handler;
32 import android.os.IRemoteCallback;
33 import android.os.Looper;
34 import android.os.Message;
35 import android.os.ParcelUuid;
36 import android.os.PersistableBundle;
37 import android.os.RemoteException;
38 import android.os.ServiceManager;
39 import android.preference.PreferenceManager;
40 import android.provider.Settings;
41 import android.provider.Settings.Global;
42 import android.provider.Settings.SettingNotFoundException;
43 import android.service.carrier.CarrierIdentifier;
44 import android.service.carrier.CarrierService;
45 import android.service.euicc.EuiccProfileInfo;
46 import android.service.euicc.EuiccService;
47 import android.service.euicc.GetEuiccProfileInfoListResult;
48 import android.telephony.CarrierConfigManager;
49 import android.telephony.Rlog;
50 import android.telephony.SubscriptionInfo;
51 import android.telephony.SubscriptionManager;
52 import android.telephony.TelephonyManager;
53 import android.telephony.UiccAccessRule;
54 import android.telephony.euicc.EuiccManager;
55 import android.text.TextUtils;
56 
57 import com.android.internal.annotations.VisibleForTesting;
58 import com.android.internal.telephony.euicc.EuiccController;
59 import com.android.internal.telephony.metrics.TelephonyMetrics;
60 import com.android.internal.telephony.uicc.IccRecords;
61 import com.android.internal.telephony.uicc.IccUtils;
62 import com.android.internal.telephony.uicc.UiccCard;
63 import com.android.internal.telephony.uicc.UiccController;
64 import com.android.internal.telephony.uicc.UiccSlot;
65 
66 import java.io.FileDescriptor;
67 import java.io.PrintWriter;
68 import java.util.ArrayList;
69 import java.util.List;
70 
71 /**
72  *@hide
73  */
74 public class SubscriptionInfoUpdater extends Handler {
75     private static final String LOG_TAG = "SubscriptionInfoUpdater";
76     @UnsupportedAppUsage
77     private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount();
78 
79     private static final boolean DBG = true;
80 
81     private static final int EVENT_INVALID = -1;
82     private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2;
83     private static final int EVENT_SIM_LOADED = 3;
84     private static final int EVENT_SIM_ABSENT = 4;
85     private static final int EVENT_SIM_LOCKED = 5;
86     private static final int EVENT_SIM_IO_ERROR = 6;
87     private static final int EVENT_SIM_UNKNOWN = 7;
88     private static final int EVENT_SIM_RESTRICTED = 8;
89     private static final int EVENT_SIM_NOT_READY = 9;
90     private static final int EVENT_SIM_READY = 10;
91     private static final int EVENT_SIM_IMSI = 11;
92     private static final int EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS = 12;
93 
94     private static final String ICCID_STRING_FOR_NO_SIM = "";
95 
96     private static final ParcelUuid REMOVE_GROUP_UUID =
97             ParcelUuid.fromString(CarrierConfigManager.REMOVE_GROUP_UUID_STRING);
98 
99     // Key used to read/write the current IMSI. Updated on SIM_STATE_CHANGED - LOADED.
100     public static final String CURR_SUBID = "curr_subid";
101 
102     @UnsupportedAppUsage
103     private static Phone[] mPhone;
104     @UnsupportedAppUsage
105     private static Context mContext = null;
106     @UnsupportedAppUsage
107     private static String mIccId[] = new String[PROJECT_SIM_NUM];
108     private static int[] sSimCardState = new int[PROJECT_SIM_NUM];
109     private static int[] sSimApplicationState = new int[PROJECT_SIM_NUM];
110     private static boolean sIsSubInfoInitialized = false;
111     private SubscriptionManager mSubscriptionManager = null;
112     private EuiccManager mEuiccManager;
113     @UnsupportedAppUsage
114     private IPackageManager mPackageManager;
115     private Handler mBackgroundHandler;
116 
117     // The current foreground user ID.
118     @UnsupportedAppUsage
119     private int mCurrentlyActiveUserId;
120     private CarrierServiceBindHelper mCarrierServiceBindHelper;
121 
122     /**
123      * Runnable with a boolean parameter. This is used in
124      * updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback).
125      */
126     private interface UpdateEmbeddedSubsCallback {
127         /**
128          * Callback of the Runnable.
129          * @param hasChanges Whether there is any subscription info change. If yes, we need to
130          * notify the listeners.
131          */
run(boolean hasChanges)132         void run(boolean hasChanges);
133     }
134 
135     // TODO: The SubscriptionController instance should be passed in here from PhoneFactory
136     // rather than invoking the static getter all over the place.
SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci)137     public SubscriptionInfoUpdater(
138             Looper looper, Context context, Phone[] phone, CommandsInterface[] ci) {
139         this(looper, context, phone, ci,
140                 IPackageManager.Stub.asInterface(ServiceManager.getService("package")));
141     }
142 
SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci, IPackageManager packageMgr)143     @VisibleForTesting public SubscriptionInfoUpdater(
144             Looper looper, Context context, Phone[] phone,
145             CommandsInterface[] ci, IPackageManager packageMgr) {
146         logd("Constructor invoked");
147         mBackgroundHandler = new Handler(looper);
148 
149         mContext = context;
150         mPhone = phone;
151         mSubscriptionManager = SubscriptionManager.from(mContext);
152         mEuiccManager = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE);
153         mPackageManager = packageMgr;
154 
155         mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
156         initializeCarrierApps();
157     }
158 
initializeCarrierApps()159     private void initializeCarrierApps() {
160         // Initialize carrier apps:
161         // -Now (on system startup)
162         // -Whenever new carrier privilege rules might change (new SIM is loaded)
163         // -Whenever we switch to a new user
164         mCurrentlyActiveUserId = 0;
165         try {
166             ActivityManager.getService().registerUserSwitchObserver(new UserSwitchObserver() {
167                 @Override
168                 public void onUserSwitching(int newUserId, IRemoteCallback reply)
169                         throws RemoteException {
170                     mCurrentlyActiveUserId = newUserId;
171                     CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
172                             mPackageManager, TelephonyManager.getDefault(),
173                             mContext.getContentResolver(), mCurrentlyActiveUserId);
174 
175                     if (reply != null) {
176                         try {
177                             reply.sendResult(null);
178                         } catch (RemoteException e) {
179                         }
180                     }
181                 }
182             }, LOG_TAG);
183             mCurrentlyActiveUserId = ActivityManager.getService().getCurrentUser().id;
184         } catch (RemoteException e) {
185             logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage());
186         }
187         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
188                 mPackageManager, TelephonyManager.getDefault(), mContext.getContentResolver(),
189                 mCurrentlyActiveUserId);
190     }
191 
192     /**
193      * Update subscriptions when given a new ICC state.
194      */
updateInternalIccState(String simStatus, String reason, int slotId, boolean absentAndInactive)195     public void updateInternalIccState(String simStatus, String reason, int slotId,
196             boolean absentAndInactive) {
197         logd("updateInternalIccState to simStatus " + simStatus + " reason " + reason
198                 + " slotId " + slotId);
199         int message = internalIccStateToMessage(simStatus);
200         if (message != EVENT_INVALID) {
201             sendMessage(obtainMessage(message, slotId, absentAndInactive ? 1 : 0, reason));
202         }
203     }
204 
internalIccStateToMessage(String simStatus)205     private int internalIccStateToMessage(String simStatus) {
206         switch(simStatus) {
207             case IccCardConstants.INTENT_VALUE_ICC_ABSENT: return EVENT_SIM_ABSENT;
208             case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: return EVENT_SIM_UNKNOWN;
209             case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: return EVENT_SIM_IO_ERROR;
210             case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: return EVENT_SIM_RESTRICTED;
211             case IccCardConstants.INTENT_VALUE_ICC_NOT_READY: return EVENT_SIM_NOT_READY;
212             case IccCardConstants.INTENT_VALUE_ICC_LOCKED: return EVENT_SIM_LOCKED;
213             case IccCardConstants.INTENT_VALUE_ICC_LOADED: return EVENT_SIM_LOADED;
214             case IccCardConstants.INTENT_VALUE_ICC_READY: return EVENT_SIM_READY;
215             case IccCardConstants.INTENT_VALUE_ICC_IMSI: return EVENT_SIM_IMSI;
216             default:
217                 logd("Ignoring simStatus: " + simStatus);
218                 return EVENT_INVALID;
219         }
220     }
221 
222     @UnsupportedAppUsage
isAllIccIdQueryDone()223     private boolean isAllIccIdQueryDone() {
224         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
225             UiccSlot slot = UiccController.getInstance().getUiccSlotForPhone(i);
226             int slotId = UiccController.getInstance().getSlotIdFromPhoneId(i);
227             if  (mIccId[i] == null || slot == null || !slot.isActive()) {
228                 if (mIccId[i] == null) {
229                     logd("Wait for SIM " + i + " Iccid");
230                 } else {
231                     logd(String.format("Wait for slot corresponding to phone %d to be active, "
232                             + "slotId is %d", i, slotId));
233                 }
234                 return false;
235             }
236         }
237         logd("All IccIds query complete");
238 
239         return true;
240     }
241 
242     @Override
handleMessage(Message msg)243     public void handleMessage(Message msg) {
244         List<Integer> cardIds = new ArrayList<>();
245         switch (msg.what) {
246             case EVENT_GET_NETWORK_SELECTION_MODE_DONE: {
247                 AsyncResult ar = (AsyncResult)msg.obj;
248                 Integer slotId = (Integer)ar.userObj;
249                 if (ar.exception == null && ar.result != null) {
250                     int[] modes = (int[])ar.result;
251                     if (modes[0] == 1) {  // Manual mode.
252                         mPhone[slotId].setNetworkSelectionModeAutomatic(null);
253                     }
254                 } else {
255                     logd("EVENT_GET_NETWORK_SELECTION_MODE_DONE: error getting network mode.");
256                 }
257                 break;
258             }
259 
260             case EVENT_SIM_LOADED:
261                 handleSimLoaded(msg.arg1);
262                 break;
263 
264             case EVENT_SIM_ABSENT:
265                 handleSimAbsent(msg.arg1, msg.arg2);
266                 break;
267 
268             case EVENT_SIM_LOCKED:
269                 handleSimLocked(msg.arg1, (String) msg.obj);
270                 break;
271 
272             case EVENT_SIM_UNKNOWN:
273                 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null);
274                 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN);
275                 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN);
276                 updateSubscriptionCarrierId(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
277                 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
278                 break;
279 
280             case EVENT_SIM_IO_ERROR:
281                 handleSimError(msg.arg1);
282                 break;
283 
284             case EVENT_SIM_RESTRICTED:
285                 broadcastSimStateChanged(msg.arg1,
286                         IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED,
287                         IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED);
288                 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_CARD_RESTRICTED);
289                 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
290                 updateSubscriptionCarrierId(msg.arg1,
291                         IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED);
292                 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED);
293                 break;
294 
295             case EVENT_SIM_READY:
296                 cardIds.add(getCardIdFromPhoneId(msg.arg1));
297                 updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
298                     if (hasChanges) {
299                         SubscriptionController.getInstance().notifySubscriptionInfoChanged();
300                     }
301                 });
302                 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null);
303                 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
304                 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
305                 break;
306 
307             case EVENT_SIM_IMSI:
308                 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
309                 break;
310 
311             case EVENT_SIM_NOT_READY:
312                 // an eUICC with no active subscriptions never becomes ready, so we need to trigger
313                 // the embedded subscriptions update here
314                 cardIds.add(getCardIdFromPhoneId(msg.arg1));
315                 updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
316                     if (hasChanges) {
317                         SubscriptionController.getInstance().notifySubscriptionInfoChanged();
318                     }
319                 });
320                 handleSimNotReady(msg.arg1);
321                 break;
322 
323             case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS:
324                 cardIds.add(msg.arg1);
325                 Runnable r = (Runnable) msg.obj;
326                 updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
327                     if (hasChanges) {
328                         SubscriptionController.getInstance().notifySubscriptionInfoChanged();
329                     }
330                     if (r != null) {
331                         r.run();
332                     }
333                 });
334                 break;
335 
336             default:
337                 logd("Unknown msg:" + msg.what);
338         }
339     }
340 
getCardIdFromPhoneId(int phoneId)341     private int getCardIdFromPhoneId(int phoneId) {
342         UiccController uiccController = UiccController.getInstance();
343         UiccCard card = uiccController.getUiccCardForPhone(phoneId);
344         if (card != null) {
345             return uiccController.convertToPublicCardId(card.getCardId());
346         }
347         return TelephonyManager.UNINITIALIZED_CARD_ID;
348     }
349 
requestEmbeddedSubscriptionInfoListRefresh(int cardId, @Nullable Runnable callback)350     void requestEmbeddedSubscriptionInfoListRefresh(int cardId, @Nullable Runnable callback) {
351         sendMessage(obtainMessage(
352                 EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, cardId, 0 /* arg2 */, callback));
353     }
354 
handleSimLocked(int slotId, String reason)355     private void handleSimLocked(int slotId, String reason) {
356         if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
357             logd("SIM" + (slotId + 1) + " hot plug in");
358             mIccId[slotId] = null;
359         }
360 
361         String iccId = mIccId[slotId];
362         if (iccId == null) {
363             IccCard iccCard = mPhone[slotId].getIccCard();
364             if (iccCard == null) {
365                 logd("handleSimLocked: IccCard null");
366                 return;
367             }
368             IccRecords records = iccCard.getIccRecords();
369             if (records == null) {
370                 logd("handleSimLocked: IccRecords null");
371                 return;
372             }
373             if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) {
374                 logd("handleSimLocked: IccID null");
375                 return;
376             }
377             mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId());
378         } else {
379             logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId);
380         }
381 
382         updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);
383 
384         broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason);
385         broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT);
386         broadcastSimApplicationStateChanged(slotId, getSimStateFromLockedReason(reason));
387         updateSubscriptionCarrierId(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED);
388         updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED);
389     }
390 
getSimStateFromLockedReason(String lockedReason)391     private static int getSimStateFromLockedReason(String lockedReason) {
392         switch (lockedReason) {
393             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN:
394                 return TelephonyManager.SIM_STATE_PIN_REQUIRED;
395             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK:
396                 return TelephonyManager.SIM_STATE_PUK_REQUIRED;
397             case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK:
398                 return TelephonyManager.SIM_STATE_NETWORK_LOCKED;
399             case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED:
400                 return TelephonyManager.SIM_STATE_PERM_DISABLED;
401             default:
402                 Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason);
403                 return TelephonyManager.SIM_STATE_UNKNOWN;
404         }
405     }
406 
handleSimNotReady(int slotId)407     private void handleSimNotReady(int slotId) {
408         logd("handleSimNotReady: slotId: " + slotId);
409 
410         IccCard iccCard = mPhone[slotId].getIccCard();
411         if (iccCard.isEmptyProfile()) {
412             // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
413             // phase, the subscription list is accessible. Treating NOT_READY
414             // as equivalent to ABSENT, once the rest of the system can handle it.
415             mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
416             updateSubscriptionInfoByIccId(slotId, false /* updateEmbeddedSubs */);
417         }
418 
419         broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
420                 null);
421         broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT);
422         broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
423     }
424 
handleSimLoaded(int slotId)425     private void handleSimLoaded(int slotId) {
426         logd("handleSimLoaded: slotId: " + slotId);
427 
428         // The SIM should be loaded at this state, but it is possible in cases such as SIM being
429         // removed or a refresh RESET that the IccRecords could be null. The right behavior is to
430         // not broadcast the SIM loaded.
431         int loadedSlotId = slotId;
432         IccCard iccCard = mPhone[slotId].getIccCard();
433         if (iccCard == null) {  // Possibly a race condition.
434             logd("handleSimLoaded: IccCard null");
435             return;
436         }
437         IccRecords records = iccCard.getIccRecords();
438         if (records == null) {  // Possibly a race condition.
439             logd("handleSimLoaded: IccRecords null");
440             return;
441         }
442         if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) {
443             logd("handleSimLoaded: IccID null");
444             return;
445         }
446         mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId());
447 
448         updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);
449         List<SubscriptionInfo> subscriptionInfos = SubscriptionController.getInstance()
450                 .getSubInfoUsingSlotIndexPrivileged(slotId);
451         if (subscriptionInfos == null || subscriptionInfos.isEmpty()) {
452             loge("empty subinfo for slotId: " + slotId + "could not update ContentResolver");
453         } else {
454             for (SubscriptionInfo sub : subscriptionInfos) {
455                 int subId = sub.getSubscriptionId();
456                 TelephonyManager tm = (TelephonyManager)
457                         mContext.getSystemService(Context.TELEPHONY_SERVICE);
458                 String operator = tm.getSimOperatorNumeric(subId);
459 
460                 if (!TextUtils.isEmpty(operator)) {
461                     if (subId == SubscriptionController.getInstance().getDefaultSubId()) {
462                         MccTable.updateMccMncConfiguration(mContext, operator);
463                     }
464                     SubscriptionController.getInstance().setMccMnc(operator, subId);
465                 } else {
466                     logd("EVENT_RECORDS_LOADED Operator name is null");
467                 }
468 
469                 String iso = tm.getSimCountryIsoForPhone(slotId);
470 
471                 if (!TextUtils.isEmpty(iso)) {
472                     SubscriptionController.getInstance().setCountryIso(iso, subId);
473                 } else {
474                     logd("EVENT_RECORDS_LOADED sim country iso is null");
475                 }
476 
477                 String msisdn = tm.getLine1Number(subId);
478                 if (msisdn != null) {
479                     SubscriptionController.getInstance().setDisplayNumber(msisdn, subId);
480                 }
481 
482                 String imsi = tm.createForSubscriptionId(subId).getSubscriberId();
483                 if (imsi != null) {
484                     SubscriptionController.getInstance().setImsi(imsi, subId);
485                 }
486 
487                 String[] ehplmns = records.getEhplmns();
488                 String[] hplmns = records.getPlmnsFromHplmnActRecord();
489                 if (ehplmns != null || hplmns != null) {
490                     SubscriptionController.getInstance().setAssociatedPlmns(ehplmns, hplmns, subId);
491                 }
492 
493                 /* Update preferred network type and network selection mode on SIM change.
494                  * Storing last subId in SharedPreference for now to detect SIM change.
495                  */
496                 SharedPreferences sp =
497                         PreferenceManager.getDefaultSharedPreferences(mContext);
498                 int storedSubId = sp.getInt(CURR_SUBID + slotId, -1);
499 
500                 if (storedSubId != subId) {
501                     int networkType = Settings.Global.getInt(
502                             mPhone[slotId].getContext().getContentResolver(),
503                             Settings.Global.PREFERRED_NETWORK_MODE + subId,
504                             -1 /* invalid network mode */);
505 
506                     if (networkType == -1) {
507                         networkType = RILConstants.PREFERRED_NETWORK_MODE;
508                         try {
509                             networkType = TelephonyManager.getIntAtIndex(
510                                     mContext.getContentResolver(),
511                                     Settings.Global.PREFERRED_NETWORK_MODE, slotId);
512                         } catch (SettingNotFoundException retrySnfe) {
513                             Rlog.e(LOG_TAG, "Settings Exception Reading Value At Index for "
514                                     + "Settings.Global.PREFERRED_NETWORK_MODE");
515                         }
516                         Settings.Global.putInt(
517                                 mPhone[slotId].getContext().getContentResolver(),
518                                 Global.PREFERRED_NETWORK_MODE + subId,
519                                 networkType);
520                     }
521 
522                     // Set the modem network mode
523                     mPhone[slotId].setPreferredNetworkType(networkType, null);
524 
525                     // Only support automatic selection mode on SIM change.
526                     mPhone[slotId].getNetworkSelectionMode(
527                             obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE,
528                                     new Integer(slotId)));
529 
530                     // Update stored subId
531                     SharedPreferences.Editor editor = sp.edit();
532                     editor.putInt(CURR_SUBID + slotId, subId);
533                     editor.apply();
534                 }
535             }
536         }
537 
538         // Update set of enabled carrier apps now that the privilege rules may have changed.
539         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
540                 mPackageManager, TelephonyManager.getDefault(),
541                 mContext.getContentResolver(), mCurrentlyActiveUserId);
542 
543         /**
544          * The sim loading sequence will be
545          *  1. ACTION_SUBINFO_CONTENT_CHANGE happens through updateSubscriptionInfoByIccId() above.
546          *  2. ACTION_SIM_STATE_CHANGED/ACTION_SIM_CARD_STATE_CHANGED
547          *  /ACTION_SIM_APPLICATION_STATE_CHANGED
548          *  3. ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED
549          *  4. ACTION_CARRIER_CONFIG_CHANGED
550          */
551         broadcastSimStateChanged(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
552         broadcastSimCardStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_PRESENT);
553         broadcastSimApplicationStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_LOADED);
554         updateSubscriptionCarrierId(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
555         updateCarrierServices(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
556     }
557 
updateCarrierServices(int slotId, String simState)558     private void updateCarrierServices(int slotId, String simState) {
559         CarrierConfigManager configManager =
560                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
561         configManager.updateConfigForPhoneId(slotId, simState);
562         mCarrierServiceBindHelper.updateForPhoneId(slotId, simState);
563     }
564 
updateSubscriptionCarrierId(int slotId, String simState)565     private void updateSubscriptionCarrierId(int slotId, String simState) {
566         if (mPhone != null && mPhone[slotId] != null) {
567             mPhone[slotId].resolveSubscriptionCarrierId(simState);
568         }
569     }
570 
handleSimAbsent(int slotId, int absentAndInactive)571     private void handleSimAbsent(int slotId, int absentAndInactive) {
572         if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
573             logd("SIM" + (slotId + 1) + " hot plug out, absentAndInactive=" + absentAndInactive);
574         }
575         mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
576         updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);
577         // Do not broadcast if the SIM is absent and inactive, because the logical slotId here is
578         // no longer correct
579         if (absentAndInactive == 0) {
580             broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT, null);
581             broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_ABSENT);
582             broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_UNKNOWN);
583             updateSubscriptionCarrierId(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
584             updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
585         }
586     }
587 
handleSimError(int slotId)588     private void handleSimError(int slotId) {
589         if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
590             logd("SIM" + (slotId + 1) + " Error ");
591         }
592         mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
593         updateSubscriptionInfoByIccId(slotId, true /* updateEmbeddedSubs */);
594         broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR,
595                 IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
596         broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR);
597         broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
598         updateSubscriptionCarrierId(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
599         updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
600     }
601 
updateSubscriptionInfoByIccId(int slotIndex, boolean updateEmbeddedSubs)602     private synchronized void updateSubscriptionInfoByIccId(int slotIndex,
603             boolean updateEmbeddedSubs) {
604         logd("updateSubscriptionInfoByIccId:+ Start");
605         if (!SubscriptionManager.isValidSlotIndex(slotIndex)) {
606             loge("[updateSubscriptionInfoByIccId]- invalid slotIndex=" + slotIndex);
607             return;
608         }
609         logd("updateSubscriptionInfoByIccId: removing subscription info record: slotIndex "
610                 + slotIndex);
611         // Clear slotIndex only when sim absent is not enough. It's possible to switch SIM profile
612         // within the same slot. Need to clear the slot index of the previous sub. Thus always clear
613         // for the changing slot first.
614         SubscriptionController.getInstance().clearSubInfoRecord(slotIndex);
615 
616         // If SIM is not absent, insert new record or update existing record.
617         if (!ICCID_STRING_FOR_NO_SIM.equals(mIccId[slotIndex])) {
618            logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: "
619                     + mIccId[slotIndex] + "slot: " + slotIndex);
620            mSubscriptionManager.addSubscriptionInfoRecord(mIccId[slotIndex], slotIndex);
621         }
622 
623         List<SubscriptionInfo> subInfos = SubscriptionController.getInstance()
624                 .getSubInfoUsingSlotIndexPrivileged(slotIndex);
625         if (subInfos != null) {
626             boolean changed = false;
627             for (int i = 0; i < subInfos.size(); i++) {
628                 SubscriptionInfo temp = subInfos.get(i);
629                 ContentValues value = new ContentValues(1);
630 
631                 String msisdn = TelephonyManager.getDefault().getLine1Number(
632                         temp.getSubscriptionId());
633 
634                 if (!TextUtils.equals(msisdn, temp.getNumber())) {
635                     value.put(SubscriptionManager.NUMBER, msisdn);
636                     mContext.getContentResolver().update(SubscriptionManager.getUriForSubscriptionId(
637                             temp.getSubscriptionId()), value, null, null);
638                     changed = true;
639                 }
640             }
641             if (changed) {
642                 // refresh Cached Active Subscription Info List
643                 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
644             }
645         }
646 
647         // TODO investigate if we can update for each slot separately.
648         if (isAllIccIdQueryDone()) {
649             // Ensure the modems are mapped correctly
650             if (mSubscriptionManager.isActiveSubId(
651                     mSubscriptionManager.getDefaultDataSubscriptionId())) {
652                 mSubscriptionManager.setDefaultDataSubId(
653                         mSubscriptionManager.getDefaultDataSubscriptionId());
654             } else {
655                 logd("bypass reset default data sub if inactive");
656             }
657             setSubInfoInitialized();
658         }
659 
660         UiccController uiccController = UiccController.getInstance();
661         UiccSlot[] uiccSlots = uiccController.getUiccSlots();
662         if (uiccSlots != null && updateEmbeddedSubs) {
663             List<Integer> cardIds = new ArrayList<>();
664             for (UiccSlot uiccSlot : uiccSlots) {
665                 if (uiccSlot != null && uiccSlot.getUiccCard() != null) {
666                     int cardId = uiccController.convertToPublicCardId(
667                             uiccSlot.getUiccCard().getCardId());
668                     cardIds.add(cardId);
669                 }
670             }
671             updateEmbeddedSubscriptions(cardIds, (hasChanges) -> {
672                 if (hasChanges) {
673                     SubscriptionController.getInstance().notifySubscriptionInfoChanged();
674                 }
675                 if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete");
676             });
677         }
678 
679         SubscriptionController.getInstance().notifySubscriptionInfoChanged();
680         if (DBG) logd("updateSubscriptionInfoByIccId: SubscriptionInfo update complete");
681     }
682 
setSubInfoInitialized()683     private static void setSubInfoInitialized() {
684         // Should only be triggered once.
685         if (!sIsSubInfoInitialized) {
686             if (DBG) logd("SubInfo Initialized");
687             sIsSubInfoInitialized = true;
688             SubscriptionController.getInstance().notifySubInfoReady();
689             MultiSimSettingController.getInstance().notifyAllSubscriptionLoaded();
690         }
691     }
692 
693     /**
694      * Whether subscriptions of all SIMs are initialized.
695      */
isSubInfoInitialized()696     public static boolean isSubInfoInitialized() {
697         return sIsSubInfoInitialized;
698     }
699 
700     /**
701      * Updates the cached list of embedded subscription for the eUICC with the given list of card
702      * IDs {@code cardIds}. The step of reading the embedded subscription list from eUICC card is
703      * executed in background thread. The callback {@code callback} is executed after the cache is
704      * refreshed. The callback is executed in main thread.
705      */
706     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
updateEmbeddedSubscriptions(List<Integer> cardIds, @Nullable UpdateEmbeddedSubsCallback callback)707     public void updateEmbeddedSubscriptions(List<Integer> cardIds,
708             @Nullable UpdateEmbeddedSubsCallback callback) {
709         // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they
710         // are filtered out of list calls as long as EuiccManager.isEnabled returns false).
711         if (!mEuiccManager.isEnabled()) {
712             callback.run(false /* hasChanges */);
713             return;
714         }
715 
716         mBackgroundHandler.post(() -> {
717             List<GetEuiccProfileInfoListResult> results = new ArrayList<>();
718             for (int cardId : cardIds) {
719                 GetEuiccProfileInfoListResult result =
720                         EuiccController.get().blockingGetEuiccProfileInfoList(cardId);
721                 if (DBG) logd("blockingGetEuiccProfileInfoList cardId " + cardId);
722                 results.add(result);
723             }
724 
725             // The runnable will be executed in the main thread.
726             this.post(() -> {
727                 boolean hasChanges = false;
728                 for (GetEuiccProfileInfoListResult result : results) {
729                     if (updateEmbeddedSubscriptionsCache(result)) {
730                         hasChanges = true;
731                     }
732                 }
733                 // The latest state in the main thread may be changed when the callback is
734                 // triggered.
735                 if (callback != null) {
736                     callback.run(hasChanges);
737                 }
738             });
739         });
740     }
741 
742     /**
743      * Update the cached list of embedded subscription based on the passed in
744      * GetEuiccProfileInfoListResult {@code result}.
745      *
746      * @return true if changes may have been made. This is not a guarantee that changes were made,
747      * but notifications about subscription changes may be skipped if this returns false as an
748      * optimization to avoid spurious notifications.
749      */
updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result)750     private boolean updateEmbeddedSubscriptionsCache(GetEuiccProfileInfoListResult result) {
751         if (DBG) logd("updateEmbeddedSubscriptionsCache");
752 
753         if (result == null) {
754             // IPC to the eUICC controller failed.
755             return false;
756         }
757 
758         // If the returned result is not RESULT_OK or the profile list is null, don't update cache.
759         // Otherwise, update the cache.
760         final EuiccProfileInfo[] embeddedProfiles;
761         List<EuiccProfileInfo> list = result.getProfiles();
762         if (result.getResult() == EuiccService.RESULT_OK && list != null) {
763             embeddedProfiles = list.toArray(new EuiccProfileInfo[list.size()]);
764             if (DBG) {
765                 logd("blockingGetEuiccProfileInfoList: got " + result.getProfiles().size()
766                         + " profiles");
767             }
768         } else {
769             if (DBG) {
770                 logd("blockingGetEuiccProfileInfoList returns an error. "
771                         + "Result code=" + result.getResult()
772                         + ". Null profile list=" + (result.getProfiles() == null));
773             }
774             return false;
775         }
776 
777         final boolean isRemovable = result.getIsRemovable();
778 
779         final String[] embeddedIccids = new String[embeddedProfiles.length];
780         for (int i = 0; i < embeddedProfiles.length; i++) {
781             embeddedIccids[i] = embeddedProfiles[i].getIccid();
782         }
783 
784         if (DBG) logd("Get eUICC profile list of size " + embeddedProfiles.length);
785 
786         // Note that this only tracks whether we make any writes to the DB. It's possible this will
787         // be set to true for an update even when the row contents remain exactly unchanged from
788         // before, since we don't compare against the previous value. Since this is only intended to
789         // avoid some spurious broadcasts (particularly for users who don't use eSIM at all), this
790         // is fine.
791         boolean hasChanges = false;
792 
793         // Update or insert records for all embedded subscriptions (except non-removable ones if the
794         // current eUICC is non-removable, since we assume these are still accessible though not
795         // returned by the eUICC controller).
796         List<SubscriptionInfo> existingSubscriptions = SubscriptionController.getInstance()
797                 .getSubscriptionInfoListForEmbeddedSubscriptionUpdate(embeddedIccids, isRemovable);
798         ContentResolver contentResolver = mContext.getContentResolver();
799         for (EuiccProfileInfo embeddedProfile : embeddedProfiles) {
800             int index =
801                     findSubscriptionInfoForIccid(existingSubscriptions, embeddedProfile.getIccid());
802             int prevCarrierId = TelephonyManager.UNKNOWN_CARRIER_ID;
803             int nameSource = SubscriptionManager.NAME_SOURCE_DEFAULT_SOURCE;
804             if (index < 0) {
805                 // No existing entry for this ICCID; create an empty one.
806                 SubscriptionController.getInstance().insertEmptySubInfoRecord(
807                         embeddedProfile.getIccid(), SubscriptionManager.SIM_NOT_INSERTED);
808             } else {
809                 nameSource = existingSubscriptions.get(index).getNameSource();
810                 prevCarrierId = existingSubscriptions.get(index).getCarrierId();
811                 existingSubscriptions.remove(index);
812             }
813 
814             if (DBG) {
815                 logd("embeddedProfile " + embeddedProfile + " existing record "
816                         + (index < 0 ? "not found" : "found"));
817             }
818 
819             ContentValues values = new ContentValues();
820             values.put(SubscriptionManager.IS_EMBEDDED, 1);
821             List<UiccAccessRule> ruleList = embeddedProfile.getUiccAccessRules();
822             boolean isRuleListEmpty = false;
823             if (ruleList == null || ruleList.size() == 0) {
824                 isRuleListEmpty = true;
825             }
826             values.put(SubscriptionManager.ACCESS_RULES,
827                     isRuleListEmpty ? null : UiccAccessRule.encodeRules(
828                             ruleList.toArray(new UiccAccessRule[ruleList.size()])));
829             values.put(SubscriptionManager.IS_REMOVABLE, isRemovable);
830             // override DISPLAY_NAME if the priority of existing nameSource is <= carrier
831             if (SubscriptionController.getNameSourcePriority(nameSource)
832                     <= SubscriptionController.getNameSourcePriority(
833                             SubscriptionManager.NAME_SOURCE_CARRIER)) {
834                 values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.getNickname());
835                 values.put(SubscriptionManager.NAME_SOURCE,
836                         SubscriptionManager.NAME_SOURCE_CARRIER);
837             }
838             values.put(SubscriptionManager.PROFILE_CLASS, embeddedProfile.getProfileClass());
839             CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier();
840             if (cid != null) {
841                 // Due to the limited subscription information, carrier id identified here might
842                 // not be accurate compared with CarrierResolver. Only update carrier id if there
843                 // is no valid carrier id present.
844                 if (prevCarrierId == TelephonyManager.UNKNOWN_CARRIER_ID) {
845                     values.put(SubscriptionManager.CARRIER_ID,
846                             CarrierResolver.getCarrierIdFromIdentifier(mContext, cid));
847                 }
848                 String mcc = cid.getMcc();
849                 String mnc = cid.getMnc();
850                 values.put(SubscriptionManager.MCC_STRING, mcc);
851                 values.put(SubscriptionManager.MCC, mcc);
852                 values.put(SubscriptionManager.MNC_STRING, mnc);
853                 values.put(SubscriptionManager.MNC, mnc);
854             }
855             hasChanges = true;
856             contentResolver.update(SubscriptionManager.CONTENT_URI, values,
857                     SubscriptionManager.ICC_ID + "=\"" + embeddedProfile.getIccid() + "\"", null);
858 
859             // refresh Cached Active Subscription Info List
860             SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
861         }
862 
863         // Remove all remaining subscriptions which have embedded = true. We set embedded to false
864         // to ensure they are not returned in the list of embedded subscriptions (but keep them
865         // around in case the subscription is added back later, which is equivalent to a removable
866         // SIM being removed and reinserted).
867         if (!existingSubscriptions.isEmpty()) {
868             if (DBG) {
869                 logd("Removing existing embedded subscriptions of size"
870                         + existingSubscriptions.size());
871             }
872             List<String> iccidsToRemove = new ArrayList<>();
873             for (int i = 0; i < existingSubscriptions.size(); i++) {
874                 SubscriptionInfo info = existingSubscriptions.get(i);
875                 if (info.isEmbedded()) {
876                     if (DBG) logd("Removing embedded subscription of IccId " + info.getIccId());
877                     iccidsToRemove.add("\"" + info.getIccId() + "\"");
878                 }
879             }
880             String whereClause = SubscriptionManager.ICC_ID + " IN ("
881                     + TextUtils.join(",", iccidsToRemove) + ")";
882             ContentValues values = new ContentValues();
883             values.put(SubscriptionManager.IS_EMBEDDED, 0);
884             hasChanges = true;
885             contentResolver.update(SubscriptionManager.CONTENT_URI, values, whereClause, null);
886 
887             // refresh Cached Active Subscription Info List
888             SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
889         }
890 
891         if (DBG) logd("updateEmbeddedSubscriptions done hasChanges=" + hasChanges);
892         return hasChanges;
893     }
894 
895     /**
896      * Called by CarrierConfigLoader to update the subscription before sending a broadcast.
897      */
updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId, String configPackageName, PersistableBundle config, Message onComplete)898     public void updateSubscriptionByCarrierConfigAndNotifyComplete(int phoneId,
899             String configPackageName, PersistableBundle config, Message onComplete) {
900         post(() -> {
901             updateSubscriptionByCarrierConfig(phoneId, configPackageName, config);
902             onComplete.sendToTarget();
903         });
904     }
905 
getDefaultCarrierServicePackageName()906     private String getDefaultCarrierServicePackageName() {
907         CarrierConfigManager configManager =
908                 (CarrierConfigManager) mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
909         return configManager.getDefaultCarrierServicePackageName();
910     }
911 
isCarrierServicePackage(int phoneId, String pkgName)912     private boolean isCarrierServicePackage(int phoneId, String pkgName) {
913         if (pkgName.equals(getDefaultCarrierServicePackageName())) return false;
914 
915         List<String> carrierPackageNames = TelephonyManager.from(mContext)
916                 .getCarrierPackageNamesForIntentAndPhone(
917                         new Intent(CarrierService.CARRIER_SERVICE_INTERFACE), phoneId);
918         if (DBG) logd("Carrier Packages For Subscription = " + carrierPackageNames);
919         return carrierPackageNames != null && carrierPackageNames.contains(pkgName);
920     }
921 
922     /**
923      * Update the currently active Subscription based on information from CarrierConfig
924      */
925     @VisibleForTesting
updateSubscriptionByCarrierConfig( int phoneId, String configPackageName, PersistableBundle config)926     public void updateSubscriptionByCarrierConfig(
927             int phoneId, String configPackageName, PersistableBundle config) {
928         if (!SubscriptionManager.isValidPhoneId(phoneId)
929                 || TextUtils.isEmpty(configPackageName) || config == null) {
930             if (DBG) {
931                 logd("In updateSubscriptionByCarrierConfig(): phoneId=" + phoneId
932                         + " configPackageName=" + configPackageName + " config="
933                         + ((config == null) ? "null" : config.hashCode()));
934             }
935             return;
936         }
937 
938         SubscriptionController sc = SubscriptionController.getInstance();
939         if (sc == null) {
940             loge("SubscriptionController was null");
941             return;
942         }
943 
944         int currentSubId = sc.getSubIdUsingPhoneId(phoneId);
945         if (!SubscriptionManager.isValidSubscriptionId(currentSubId)
946                 || currentSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
947             if (DBG) logd("No subscription is active for phone being updated");
948             return;
949         }
950 
951         SubscriptionInfo currentSubInfo = sc.getSubscriptionInfo(currentSubId);
952         if (currentSubInfo == null) {
953             loge("Couldn't retrieve subscription info for current subscription");
954             return;
955         }
956 
957         if (!isCarrierServicePackage(phoneId, configPackageName)) {
958             loge("Cannot manage subId=" + currentSubId + ", carrierPackage=" + configPackageName);
959             return;
960         }
961 
962         ContentValues cv = new ContentValues();
963         boolean isOpportunistic = config.getBoolean(
964                 CarrierConfigManager.KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
965         if (currentSubInfo.isOpportunistic() != isOpportunistic) {
966             if (DBG) logd("Set SubId=" + currentSubId + " isOpportunistic=" + isOpportunistic);
967             cv.put(SubscriptionManager.IS_OPPORTUNISTIC, isOpportunistic ? "1" : "0");
968         }
969 
970         String groupUuidString =
971                 config.getString(CarrierConfigManager.KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
972         ParcelUuid groupUuid = null;
973         if (!TextUtils.isEmpty(groupUuidString)) {
974             try {
975                 // Update via a UUID Structure to ensure consistent formatting
976                 groupUuid = ParcelUuid.fromString(groupUuidString);
977                 if (groupUuid.equals(REMOVE_GROUP_UUID)
978                             && currentSubInfo.getGroupUuid() != null) {
979                     cv.put(SubscriptionManager.GROUP_UUID, (String) null);
980                     if (DBG) logd("Group Removed for" + currentSubId);
981                 } else if (SubscriptionController.getInstance().canPackageManageGroup(groupUuid,
982                         configPackageName)) {
983                     cv.put(SubscriptionManager.GROUP_UUID, groupUuid.toString());
984                     cv.put(SubscriptionManager.GROUP_OWNER, configPackageName);
985                     if (DBG) logd("Group Added for" + currentSubId);
986                 } else {
987                     loge("configPackageName " + configPackageName + " doesn't own grouUuid "
988                             + groupUuid);
989                 }
990             } catch (IllegalArgumentException e) {
991                 loge("Invalid Group UUID=" + groupUuidString);
992             }
993         }
994         if (cv.size() > 0 && mContext.getContentResolver().update(SubscriptionManager
995                     .getUriForSubscriptionId(currentSubId), cv, null, null) > 0) {
996             sc.refreshCachedActiveSubscriptionInfoList();
997             sc.notifySubscriptionInfoChanged();
998             MultiSimSettingController.getInstance().notifySubscriptionGroupChanged(groupUuid);
999         }
1000     }
1001 
findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid)1002     private static int findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid) {
1003         for (int i = 0; i < list.size(); i++) {
1004             if (TextUtils.equals(iccid, list.get(i).getIccId())) {
1005                 return i;
1006             }
1007         }
1008         return -1;
1009     }
1010 
isNewSim(String iccId, String decIccId, String[] oldIccId)1011     private boolean isNewSim(String iccId, String decIccId, String[] oldIccId) {
1012         boolean newSim = true;
1013         for(int i = 0; i < PROJECT_SIM_NUM; i++) {
1014             if(iccId.equals(oldIccId[i])) {
1015                 newSim = false;
1016                 break;
1017             } else if (decIccId != null && decIccId.equals(oldIccId[i])) {
1018                 newSim = false;
1019                 break;
1020             }
1021         }
1022         logd("newSim = " + newSim);
1023 
1024         return newSim;
1025     }
1026 
1027     @UnsupportedAppUsage
broadcastSimStateChanged(int slotId, String state, String reason)1028     private void broadcastSimStateChanged(int slotId, String state, String reason) {
1029         Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
1030         // TODO - we'd like this intent to have a single snapshot of all sim state,
1031         // but until then this should not use REPLACE_PENDING or we may lose
1032         // information
1033         // i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
1034         //         | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1035         i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1036         i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
1037         i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
1038         i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
1039         SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId);
1040         logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + reason +
1041                 " for phone: " + slotId);
1042         IntentBroadcaster.getInstance().broadcastStickyIntent(i, slotId);
1043     }
1044 
broadcastSimCardStateChanged(int phoneId, int state)1045     private void broadcastSimCardStateChanged(int phoneId, int state) {
1046         if (state != sSimCardState[phoneId]) {
1047             sSimCardState[phoneId] = state;
1048             Intent i = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
1049             i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1050             i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1051             i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
1052             SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId);
1053             // TODO(b/130664115) we manually populate this intent with the slotId. In the future we
1054             // should do a review of whether to make this public
1055             int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId);
1056             i.putExtra(PhoneConstants.SLOT_KEY, slotId);
1057             logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + simStateString(state)
1058                     + " for phone: " + phoneId + " slot: " + slotId);
1059             mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
1060             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
1061         }
1062     }
1063 
broadcastSimApplicationStateChanged(int phoneId, int state)1064     private void broadcastSimApplicationStateChanged(int phoneId, int state) {
1065         // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY,
1066         // because that's the initial state and a broadcast should be sent only on a transition
1067         // after SIM is PRESENT
1068         if (!(state == sSimApplicationState[phoneId]
1069                 || (state == TelephonyManager.SIM_STATE_NOT_READY
1070                 && sSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN))) {
1071             sSimApplicationState[phoneId] = state;
1072             Intent i = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
1073             i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
1074             i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1075             i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
1076             SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId);
1077             // TODO(b/130664115) we populate this intent with the actual slotId. In the future we
1078             // should do a review of whether to make this public
1079             int slotId = UiccController.getInstance().getSlotIdFromPhoneId(phoneId);
1080             i.putExtra(PhoneConstants.SLOT_KEY, slotId);
1081             logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + simStateString(state)
1082                     + " for phone: " + phoneId + " slot: " + slotId);
1083             mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
1084             TelephonyMetrics.getInstance().updateSimState(phoneId, state);
1085         }
1086     }
1087 
simStateString(int state)1088     private static String simStateString(int state) {
1089         switch (state) {
1090             case TelephonyManager.SIM_STATE_UNKNOWN:
1091                 return "UNKNOWN";
1092             case TelephonyManager.SIM_STATE_ABSENT:
1093                 return "ABSENT";
1094             case TelephonyManager.SIM_STATE_PIN_REQUIRED:
1095                 return "PIN_REQUIRED";
1096             case TelephonyManager.SIM_STATE_PUK_REQUIRED:
1097                 return "PUK_REQUIRED";
1098             case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
1099                 return "NETWORK_LOCKED";
1100             case TelephonyManager.SIM_STATE_READY:
1101                 return "READY";
1102             case TelephonyManager.SIM_STATE_NOT_READY:
1103                 return "NOT_READY";
1104             case TelephonyManager.SIM_STATE_PERM_DISABLED:
1105                 return "PERM_DISABLED";
1106             case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
1107                 return "CARD_IO_ERROR";
1108             case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
1109                 return "CARD_RESTRICTED";
1110             case TelephonyManager.SIM_STATE_LOADED:
1111                 return "LOADED";
1112             case TelephonyManager.SIM_STATE_PRESENT:
1113                 return "PRESENT";
1114             default:
1115                 return "INVALID";
1116         }
1117     }
1118 
1119     @UnsupportedAppUsage
logd(String message)1120     private static void logd(String message) {
1121         Rlog.d(LOG_TAG, message);
1122     }
1123 
loge(String message)1124     private static void loge(String message) {
1125         Rlog.e(LOG_TAG, message);
1126     }
1127 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1128     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1129         pw.println("SubscriptionInfoUpdater:");
1130         mCarrierServiceBindHelper.dump(fd, pw, args);
1131     }
1132 }
1133