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.app.ActivityManager;
22 import android.app.UserSwitchObserver;
23 import android.content.ContentResolver;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.content.Intent;
27 import android.content.SharedPreferences;
28 import android.content.pm.IPackageManager;
29 import android.os.AsyncResult;
30 import android.os.Handler;
31 import android.os.IRemoteCallback;
32 import android.os.Looper;
33 import android.os.Message;
34 import android.os.RemoteException;
35 import android.os.ServiceManager;
36 import android.preference.PreferenceManager;
37 import android.provider.Settings;
38 import android.provider.Settings.Global;
39 import android.provider.Settings.SettingNotFoundException;
40 import android.service.euicc.EuiccProfileInfo;
41 import android.service.euicc.EuiccService;
42 import android.service.euicc.GetEuiccProfileInfoListResult;
43 import android.telephony.CarrierConfigManager;
44 import android.telephony.Rlog;
45 import android.telephony.SubscriptionInfo;
46 import android.telephony.SubscriptionManager;
47 import android.telephony.TelephonyManager;
48 import android.telephony.UiccAccessRule;
49 import android.telephony.euicc.EuiccManager;
50 import android.text.TextUtils;
51 
52 import com.android.internal.annotations.VisibleForTesting;
53 import com.android.internal.telephony.euicc.EuiccController;
54 import com.android.internal.telephony.uicc.IccRecords;
55 import com.android.internal.telephony.uicc.IccUtils;
56 
57 import java.io.FileDescriptor;
58 import java.io.PrintWriter;
59 import java.util.ArrayList;
60 import java.util.List;
61 
62 /**
63  *@hide
64  */
65 public class SubscriptionInfoUpdater extends Handler {
66     private static final String LOG_TAG = "SubscriptionInfoUpdater";
67     private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount();
68 
69     private static final int EVENT_INVALID = -1;
70     private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2;
71     private static final int EVENT_SIM_LOADED = 3;
72     private static final int EVENT_SIM_ABSENT = 4;
73     private static final int EVENT_SIM_LOCKED = 5;
74     private static final int EVENT_SIM_IO_ERROR = 6;
75     private static final int EVENT_SIM_UNKNOWN = 7;
76     private static final int EVENT_SIM_RESTRICTED = 8;
77     private static final int EVENT_SIM_NOT_READY = 9;
78     private static final int EVENT_SIM_READY = 10;
79     private static final int EVENT_SIM_IMSI = 11;
80     private static final int EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS = 12;
81 
82     private static final String ICCID_STRING_FOR_NO_SIM = "";
83     /**
84      *  int[] sInsertSimState maintains all slots' SIM inserted status currently,
85      *  it may contain 4 kinds of values:
86      *    SIM_NOT_INSERT : no SIM inserted in slot i now
87      *    SIM_CHANGED    : a valid SIM insert in slot i and is different SIM from last time
88      *                     it will later become SIM_NEW or SIM_REPOSITION during update procedure
89      *    SIM_NOT_CHANGE : a valid SIM insert in slot i and is the same SIM as last time
90      *    SIM_NEW        : a valid SIM insert in slot i and is a new SIM
91      *    SIM_REPOSITION : a valid SIM insert in slot i and is inserted in different slot last time
92      *    positive integer #: index to distinguish SIM cards with the same IccId
93      */
94     public static final int SIM_NOT_CHANGE = 0;
95     public static final int SIM_CHANGED    = -1;
96     public static final int SIM_NEW        = -2;
97     public static final int SIM_REPOSITION = -3;
98     public static final int SIM_NOT_INSERT = -99;
99 
100     public static final int STATUS_NO_SIM_INSERTED = 0x00;
101     public static final int STATUS_SIM1_INSERTED = 0x01;
102     public static final int STATUS_SIM2_INSERTED = 0x02;
103     public static final int STATUS_SIM3_INSERTED = 0x04;
104     public static final int STATUS_SIM4_INSERTED = 0x08;
105 
106     // Key used to read/write the current IMSI. Updated on SIM_STATE_CHANGED - LOADED.
107     public static final String CURR_SUBID = "curr_subid";
108 
109     private static Phone[] mPhone;
110     private static Context mContext = null;
111     private static String mIccId[] = new String[PROJECT_SIM_NUM];
112     private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
113     private static int[] sSimCardState = new int[PROJECT_SIM_NUM];
114     private static int[] sSimApplicationState = new int[PROJECT_SIM_NUM];
115     private SubscriptionManager mSubscriptionManager = null;
116     private EuiccManager mEuiccManager;
117     private IPackageManager mPackageManager;
118 
119     // The current foreground user ID.
120     private int mCurrentlyActiveUserId;
121     private CarrierServiceBindHelper mCarrierServiceBindHelper;
122 
SubscriptionInfoUpdater( Looper looper, Context context, Phone[] phone, CommandsInterface[] ci)123     public SubscriptionInfoUpdater(
124             Looper looper, Context context, Phone[] phone, CommandsInterface[] ci) {
125         super(looper);
126         logd("Constructor invoked");
127 
128         mContext = context;
129         mPhone = phone;
130         mSubscriptionManager = SubscriptionManager.from(mContext);
131         mEuiccManager = (EuiccManager) mContext.getSystemService(Context.EUICC_SERVICE);
132         mPackageManager = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
133 
134         mCarrierServiceBindHelper = new CarrierServiceBindHelper(mContext);
135         initializeCarrierApps();
136     }
137 
initializeCarrierApps()138     private void initializeCarrierApps() {
139         // Initialize carrier apps:
140         // -Now (on system startup)
141         // -Whenever new carrier privilege rules might change (new SIM is loaded)
142         // -Whenever we switch to a new user
143         mCurrentlyActiveUserId = 0;
144         try {
145             ActivityManager.getService().registerUserSwitchObserver(new UserSwitchObserver() {
146                 @Override
147                 public void onUserSwitching(int newUserId, IRemoteCallback reply)
148                         throws RemoteException {
149                     mCurrentlyActiveUserId = newUserId;
150                     CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
151                             mPackageManager, TelephonyManager.getDefault(),
152                             mContext.getContentResolver(), mCurrentlyActiveUserId);
153 
154                     if (reply != null) {
155                         try {
156                             reply.sendResult(null);
157                         } catch (RemoteException e) {
158                         }
159                     }
160                 }
161             }, LOG_TAG);
162             mCurrentlyActiveUserId = ActivityManager.getService().getCurrentUser().id;
163         } catch (RemoteException e) {
164             logd("Couldn't get current user ID; guessing it's 0: " + e.getMessage());
165         }
166         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
167                 mPackageManager, TelephonyManager.getDefault(), mContext.getContentResolver(),
168                 mCurrentlyActiveUserId);
169     }
170 
updateInternalIccState(String simStatus, String reason, int slotId)171     public void updateInternalIccState(String simStatus, String reason, int slotId) {
172         logd("updateInternalIccState to simStatus " + simStatus + " reason " + reason
173                 + " slotId " + slotId);
174         int message = internalIccStateToMessage(simStatus);
175         if (message != EVENT_INVALID) {
176             sendMessage(obtainMessage(message, slotId, -1, reason));
177         }
178     }
179 
internalIccStateToMessage(String simStatus)180     private int internalIccStateToMessage(String simStatus) {
181         switch(simStatus) {
182             case IccCardConstants.INTENT_VALUE_ICC_ABSENT: return EVENT_SIM_ABSENT;
183             case IccCardConstants.INTENT_VALUE_ICC_UNKNOWN: return EVENT_SIM_UNKNOWN;
184             case IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR: return EVENT_SIM_IO_ERROR;
185             case IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED: return EVENT_SIM_RESTRICTED;
186             case IccCardConstants.INTENT_VALUE_ICC_NOT_READY: return EVENT_SIM_NOT_READY;
187             case IccCardConstants.INTENT_VALUE_ICC_LOCKED: return EVENT_SIM_LOCKED;
188             case IccCardConstants.INTENT_VALUE_ICC_LOADED: return EVENT_SIM_LOADED;
189             case IccCardConstants.INTENT_VALUE_ICC_READY: return EVENT_SIM_READY;
190             case IccCardConstants.INTENT_VALUE_ICC_IMSI: return EVENT_SIM_IMSI;
191             default:
192                 logd("Ignoring simStatus: " + simStatus);
193                 return EVENT_INVALID;
194         }
195     }
196 
isAllIccIdQueryDone()197     private boolean isAllIccIdQueryDone() {
198         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
199             if (mIccId[i] == null) {
200                 logd("Wait for SIM" + (i + 1) + " IccId");
201                 return false;
202             }
203         }
204         logd("All IccIds query complete");
205 
206         return true;
207     }
208 
209     @Override
handleMessage(Message msg)210     public void handleMessage(Message msg) {
211         switch (msg.what) {
212             case EVENT_GET_NETWORK_SELECTION_MODE_DONE: {
213                 AsyncResult ar = (AsyncResult)msg.obj;
214                 Integer slotId = (Integer)ar.userObj;
215                 if (ar.exception == null && ar.result != null) {
216                     int[] modes = (int[])ar.result;
217                     if (modes[0] == 1) {  // Manual mode.
218                         mPhone[slotId].setNetworkSelectionModeAutomatic(null);
219                     }
220                 } else {
221                     logd("EVENT_GET_NETWORK_SELECTION_MODE_DONE: error getting network mode.");
222                 }
223                 break;
224             }
225 
226             case EVENT_SIM_LOADED:
227                 handleSimLoaded(msg.arg1);
228                 break;
229 
230             case EVENT_SIM_ABSENT:
231                 handleSimAbsent(msg.arg1);
232                 break;
233 
234             case EVENT_SIM_LOCKED:
235                 handleSimLocked(msg.arg1, (String) msg.obj);
236                 break;
237 
238             case EVENT_SIM_UNKNOWN:
239                 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN);
240                 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_UNKNOWN, null);
241                 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN);
242                 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_UNKNOWN);
243                 break;
244 
245             case EVENT_SIM_IO_ERROR:
246                 handleSimError(msg.arg1);
247                 break;
248 
249             case EVENT_SIM_RESTRICTED:
250                 updateCarrierServices(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED);
251                 broadcastSimStateChanged(msg.arg1,
252                         IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED,
253                         IccCardConstants.INTENT_VALUE_ICC_CARD_RESTRICTED);
254                 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_CARD_RESTRICTED);
255                 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
256                 break;
257 
258             case EVENT_SIM_READY:
259                 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_READY, null);
260                 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
261                 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
262                 break;
263 
264             case EVENT_SIM_IMSI:
265                 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_IMSI, null);
266                 break;
267 
268             case EVENT_SIM_NOT_READY:
269                 broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
270                         null);
271                 broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
272                 broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
273                 // intentional fall through
274                 // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
275                 // phase, the subscription list is accessible.
276                 // TODO(b/64216093): Clean up this special case, likely by treating NOT_READY
277                 // as equivalent to ABSENT, once the rest of the system can handle it. Currently
278                 // this breaks SystemUI which shows a "No SIM" icon.
279 
280             case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS:
281                 if (updateEmbeddedSubscriptions()) {
282                     SubscriptionController.getInstance().notifySubscriptionInfoChanged();
283                 }
284                 if (msg.obj != null) {
285                     ((Runnable) msg.obj).run();
286                 }
287                 break;
288 
289             default:
290                 logd("Unknown msg:" + msg.what);
291         }
292     }
293 
requestEmbeddedSubscriptionInfoListRefresh(@ullable Runnable callback)294     void requestEmbeddedSubscriptionInfoListRefresh(@Nullable Runnable callback) {
295         sendMessage(obtainMessage(EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS, callback));
296     }
297 
handleSimLocked(int slotId, String reason)298     private void handleSimLocked(int slotId, String reason) {
299         if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
300             logd("SIM" + (slotId + 1) + " hot plug in");
301             mIccId[slotId] = null;
302         }
303 
304         String iccId = mIccId[slotId];
305         if (iccId == null) {
306             IccCard iccCard = mPhone[slotId].getIccCard();
307             if (iccCard == null) {
308                 logd("handleSimLocked: IccCard null");
309                 return;
310             }
311             IccRecords records = iccCard.getIccRecords();
312             if (records == null) {
313                 logd("handleSimLocked: IccRecords null");
314                 return;
315             }
316             if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) {
317                 logd("handleSimLocked: IccID null");
318                 return;
319             }
320             mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId());
321         } else {
322             logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId);
323         }
324 
325         if (isAllIccIdQueryDone()) {
326             updateSubscriptionInfoByIccId();
327         }
328 
329         updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED);
330         broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED, reason);
331         broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT);
332         broadcastSimApplicationStateChanged(slotId, getSimStateFromLockedReason(reason));
333     }
334 
getSimStateFromLockedReason(String lockedReason)335     private static int getSimStateFromLockedReason(String lockedReason) {
336         switch (lockedReason) {
337             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN:
338                 return TelephonyManager.SIM_STATE_PIN_REQUIRED;
339             case IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK:
340                 return TelephonyManager.SIM_STATE_PUK_REQUIRED;
341             case IccCardConstants.INTENT_VALUE_LOCKED_NETWORK:
342                 return TelephonyManager.SIM_STATE_NETWORK_LOCKED;
343             case IccCardConstants.INTENT_VALUE_ABSENT_ON_PERM_DISABLED:
344                 return TelephonyManager.SIM_STATE_PERM_DISABLED;
345             default:
346                 Rlog.e(LOG_TAG, "Unexpected SIM locked reason " + lockedReason);
347                 return TelephonyManager.SIM_STATE_UNKNOWN;
348         }
349     }
350 
handleSimLoaded(int slotId)351     private void handleSimLoaded(int slotId) {
352         logd("handleSimLoaded: slotId: " + slotId);
353 
354         // The SIM should be loaded at this state, but it is possible in cases such as SIM being
355         // removed or a refresh RESET that the IccRecords could be null. The right behavior is to
356         // not broadcast the SIM loaded.
357         int loadedSlotId = slotId;
358         IccCard iccCard = mPhone[slotId].getIccCard();
359         if (iccCard == null) {  // Possibly a race condition.
360             logd("handleSimLoaded: IccCard null");
361             return;
362         }
363         IccRecords records = iccCard.getIccRecords();
364         if (records == null) {  // Possibly a race condition.
365             logd("handleSimLoaded: IccRecords null");
366             return;
367         }
368         if (IccUtils.stripTrailingFs(records.getFullIccId()) == null) {
369             logd("handleSimLoaded: IccID null");
370             return;
371         }
372         mIccId[slotId] = IccUtils.stripTrailingFs(records.getFullIccId());
373 
374         if (isAllIccIdQueryDone()) {
375             updateSubscriptionInfoByIccId();
376             int[] subIds = mSubscriptionManager.getActiveSubscriptionIdList();
377             for (int subId : subIds) {
378                 TelephonyManager tm = TelephonyManager.getDefault();
379 
380                 String operator = tm.getSimOperatorNumeric(subId);
381                 slotId = SubscriptionController.getInstance().getPhoneId(subId);
382 
383                 if (!TextUtils.isEmpty(operator)) {
384                     if (subId == SubscriptionController.getInstance().getDefaultSubId()) {
385                         MccTable.updateMccMncConfiguration(mContext, operator, false);
386                     }
387                     SubscriptionController.getInstance().setMccMnc(operator, subId);
388                 } else {
389                     logd("EVENT_RECORDS_LOADED Operator name is null");
390                 }
391 
392                 String msisdn = tm.getLine1Number(subId);
393                 ContentResolver contentResolver = mContext.getContentResolver();
394 
395                 if (msisdn != null) {
396                     SubscriptionController.getInstance().setDisplayNumber(msisdn, subId);
397                 }
398 
399                 SubscriptionInfo subInfo = mSubscriptionManager.getActiveSubscriptionInfo(subId);
400                 String nameToSet;
401                 String simCarrierName = tm.getSimOperatorName(subId);
402 
403                 if (subInfo != null && subInfo.getNameSource() !=
404                         SubscriptionManager.NAME_SOURCE_USER_INPUT) {
405                     if (!TextUtils.isEmpty(simCarrierName)) {
406                         nameToSet = simCarrierName;
407                     } else {
408                         nameToSet = "CARD " + Integer.toString(slotId + 1);
409                     }
410                     logd("sim name = " + nameToSet);
411                     SubscriptionController.getInstance().setDisplayName(nameToSet, subId);
412                 }
413 
414                 /* Update preferred network type and network selection mode on SIM change.
415                  * Storing last subId in SharedPreference for now to detect SIM change. */
416                 SharedPreferences sp =
417                         PreferenceManager.getDefaultSharedPreferences(mContext);
418                 int storedSubId = sp.getInt(CURR_SUBID + slotId, -1);
419 
420                 if (storedSubId != subId) {
421                     int networkType = Settings.Global.getInt(
422                             mPhone[slotId].getContext().getContentResolver(),
423                             Settings.Global.PREFERRED_NETWORK_MODE + subId,
424                             -1 /* invalid network mode */);
425 
426                     if (networkType == -1) {
427                         networkType = RILConstants.PREFERRED_NETWORK_MODE;
428                         try {
429                             networkType = TelephonyManager.getIntAtIndex(
430                                     mContext.getContentResolver(),
431                                     Settings.Global.PREFERRED_NETWORK_MODE, slotId);
432                         } catch (SettingNotFoundException retrySnfe) {
433                             Rlog.e(LOG_TAG, "Settings Exception Reading Value At Index for "
434                                     + "Settings.Global.PREFERRED_NETWORK_MODE");
435                         }
436                         Settings.Global.putInt(
437                                 mPhone[slotId].getContext().getContentResolver(),
438                                 Global.PREFERRED_NETWORK_MODE + subId,
439                                 networkType);
440                     }
441 
442                     // Set the modem network mode
443                     mPhone[slotId].setPreferredNetworkType(networkType, null);
444 
445                     // Only support automatic selection mode on SIM change.
446                     mPhone[slotId].getNetworkSelectionMode(
447                             obtainMessage(EVENT_GET_NETWORK_SELECTION_MODE_DONE,
448                                     new Integer(slotId)));
449 
450                     // Update stored subId
451                     SharedPreferences.Editor editor = sp.edit();
452                     editor.putInt(CURR_SUBID + slotId, subId);
453                     editor.apply();
454                 }
455             }
456         }
457 
458         // Update set of enabled carrier apps now that the privilege rules may have changed.
459         CarrierAppUtils.disableCarrierAppsUntilPrivileged(mContext.getOpPackageName(),
460                 mPackageManager, TelephonyManager.getDefault(),
461                 mContext.getContentResolver(), mCurrentlyActiveUserId);
462 
463         broadcastSimStateChanged(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
464         broadcastSimCardStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_PRESENT);
465         broadcastSimApplicationStateChanged(loadedSlotId, TelephonyManager.SIM_STATE_LOADED);
466         updateCarrierServices(loadedSlotId, IccCardConstants.INTENT_VALUE_ICC_LOADED);
467     }
468 
updateCarrierServices(int slotId, String simState)469     private void updateCarrierServices(int slotId, String simState) {
470         CarrierConfigManager configManager = (CarrierConfigManager)
471                 mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
472         configManager.updateConfigForPhoneId(slotId, simState);
473         mCarrierServiceBindHelper.updateForPhoneId(slotId, simState);
474     }
475 
handleSimAbsent(int slotId)476     private void handleSimAbsent(int slotId) {
477         if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
478             logd("SIM" + (slotId + 1) + " hot plug out");
479         }
480         mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
481         if (isAllIccIdQueryDone()) {
482             updateSubscriptionInfoByIccId();
483         }
484         updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT);
485         broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_ABSENT, null);
486         broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_ABSENT);
487         broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
488     }
489 
handleSimError(int slotId)490     private void handleSimError(int slotId) {
491         if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
492             logd("SIM" + (slotId + 1) + " Error ");
493         }
494         mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
495         if (isAllIccIdQueryDone()) {
496             updateSubscriptionInfoByIccId();
497         }
498         updateCarrierServices(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
499         broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR,
500                 IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR);
501         broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_CARD_IO_ERROR);
502         broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
503     }
504 
505     /**
506      * TODO: Simplify more, as no one is interested in what happened
507      * only what the current list contains.
508      */
updateSubscriptionInfoByIccId()509     synchronized private void updateSubscriptionInfoByIccId() {
510         logd("updateSubscriptionInfoByIccId:+ Start");
511 
512         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
513             mInsertSimState[i] = SIM_NOT_CHANGE;
514         }
515 
516         int insertedSimCount = PROJECT_SIM_NUM;
517         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
518             if (ICCID_STRING_FOR_NO_SIM.equals(mIccId[i])) {
519                 insertedSimCount--;
520                 mInsertSimState[i] = SIM_NOT_INSERT;
521             }
522         }
523         logd("insertedSimCount = " + insertedSimCount);
524 
525         // We only clear the slot-to-sub map when one/some SIM was removed. Note this is a
526         // workaround for some race conditions that the empty map was accessed while we are
527         // rebuilding the map.
528         if (SubscriptionController.getInstance().getActiveSubIdList().length > insertedSimCount) {
529             SubscriptionController.getInstance().clearSubInfo();
530         }
531 
532         int index = 0;
533         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
534             if (mInsertSimState[i] == SIM_NOT_INSERT) {
535                 continue;
536             }
537             index = 2;
538             for (int j = i + 1; j < PROJECT_SIM_NUM; j++) {
539                 if (mInsertSimState[j] == SIM_NOT_CHANGE && mIccId[i].equals(mIccId[j])) {
540                     mInsertSimState[i] = 1;
541                     mInsertSimState[j] = index;
542                     index++;
543                 }
544             }
545         }
546 
547         ContentResolver contentResolver = mContext.getContentResolver();
548         String[] oldIccId = new String[PROJECT_SIM_NUM];
549         String[] decIccId = new String[PROJECT_SIM_NUM];
550         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
551             oldIccId[i] = null;
552             List<SubscriptionInfo> oldSubInfo = SubscriptionController.getInstance()
553                     .getSubInfoUsingSlotIndexPrivileged(i, false);
554             decIccId[i] = IccUtils.getDecimalSubstring(mIccId[i]);
555             if (oldSubInfo != null && oldSubInfo.size() > 0) {
556                 oldIccId[i] = oldSubInfo.get(0).getIccId();
557                 logd("updateSubscriptionInfoByIccId: oldSubId = "
558                         + oldSubInfo.get(0).getSubscriptionId());
559                 if (mInsertSimState[i] == SIM_NOT_CHANGE && !(mIccId[i].equals(oldIccId[i])
560                             || (decIccId[i] != null && decIccId[i].equals(oldIccId[i])))) {
561                     mInsertSimState[i] = SIM_CHANGED;
562                 }
563                 if (mInsertSimState[i] != SIM_NOT_CHANGE) {
564                     ContentValues value = new ContentValues(1);
565                     value.put(SubscriptionManager.SIM_SLOT_INDEX,
566                             SubscriptionManager.INVALID_SIM_SLOT_INDEX);
567                     contentResolver.update(SubscriptionManager.CONTENT_URI, value,
568                             SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
569                             + Integer.toString(oldSubInfo.get(0).getSubscriptionId()), null);
570 
571                     // refresh Cached Active Subscription Info List
572                     SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
573                 }
574             } else {
575                 if (mInsertSimState[i] == SIM_NOT_CHANGE) {
576                     // no SIM inserted last time, but there is one SIM inserted now
577                     mInsertSimState[i] = SIM_CHANGED;
578                 }
579                 oldIccId[i] = ICCID_STRING_FOR_NO_SIM;
580                 logd("updateSubscriptionInfoByIccId: No SIM in slot " + i + " last time");
581             }
582         }
583 
584         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
585             logd("updateSubscriptionInfoByIccId: oldIccId[" + i + "] = " + oldIccId[i] +
586                     ", sIccId[" + i + "] = " + mIccId[i]);
587         }
588 
589         //check if the inserted SIM is new SIM
590         int nNewCardCount = 0;
591         int nNewSimStatus = 0;
592         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
593             if (mInsertSimState[i] == SIM_NOT_INSERT) {
594                 logd("updateSubscriptionInfoByIccId: No SIM inserted in slot " + i + " this time");
595             } else {
596                 if (mInsertSimState[i] > 0) {
597                     //some special SIMs may have the same IccIds, add suffix to distinguish them
598                     //FIXME: addSubInfoRecord can return an error.
599                     mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i]
600                             + Integer.toString(mInsertSimState[i]), i);
601                     logd("SUB" + (i + 1) + " has invalid IccId");
602                 } else /*if (sInsertSimState[i] != SIM_NOT_INSERT)*/ {
603                     logd("updateSubscriptionInfoByIccId: adding subscription info record: iccid: "
604                             + mIccId[i] + "slot: " + i);
605                     mSubscriptionManager.addSubscriptionInfoRecord(mIccId[i], i);
606                 }
607                 if (isNewSim(mIccId[i], decIccId[i], oldIccId)) {
608                     nNewCardCount++;
609                     switch (i) {
610                         case PhoneConstants.SUB1:
611                             nNewSimStatus |= STATUS_SIM1_INSERTED;
612                             break;
613                         case PhoneConstants.SUB2:
614                             nNewSimStatus |= STATUS_SIM2_INSERTED;
615                             break;
616                         case PhoneConstants.SUB3:
617                             nNewSimStatus |= STATUS_SIM3_INSERTED;
618                             break;
619                         //case PhoneConstants.SUB3:
620                         //    nNewSimStatus |= STATUS_SIM4_INSERTED;
621                         //    break;
622                     }
623 
624                     mInsertSimState[i] = SIM_NEW;
625                 }
626             }
627         }
628 
629         for (int i = 0; i < PROJECT_SIM_NUM; i++) {
630             if (mInsertSimState[i] == SIM_CHANGED) {
631                 mInsertSimState[i] = SIM_REPOSITION;
632             }
633             logd("updateSubscriptionInfoByIccId: sInsertSimState[" + i + "] = "
634                     + mInsertSimState[i]);
635         }
636 
637         List<SubscriptionInfo> subInfos = mSubscriptionManager.getActiveSubscriptionInfoList();
638         int nSubCount = (subInfos == null) ? 0 : subInfos.size();
639         logd("updateSubscriptionInfoByIccId: nSubCount = " + nSubCount);
640         for (int i=0; i < nSubCount; i++) {
641             SubscriptionInfo temp = subInfos.get(i);
642 
643             String msisdn = TelephonyManager.getDefault().getLine1Number(
644                     temp.getSubscriptionId());
645 
646             if (msisdn != null) {
647                 ContentValues value = new ContentValues(1);
648                 value.put(SubscriptionManager.NUMBER, msisdn);
649                 contentResolver.update(SubscriptionManager.CONTENT_URI, value,
650                         SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "="
651                         + Integer.toString(temp.getSubscriptionId()), null);
652 
653                 // refresh Cached Active Subscription Info List
654                 SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
655             }
656         }
657 
658         // Ensure the modems are mapped correctly
659         mSubscriptionManager.setDefaultDataSubId(
660                 mSubscriptionManager.getDefaultDataSubscriptionId());
661 
662         // No need to check return value here as we notify for the above changes anyway.
663         updateEmbeddedSubscriptions();
664 
665         SubscriptionController.getInstance().notifySubscriptionInfoChanged();
666         logd("updateSubscriptionInfoByIccId:- SubscriptionInfo update complete");
667     }
668 
669     /**
670      * Update the cached list of embedded subscriptions.
671      *
672      * @return true if changes may have been made. This is not a guarantee that changes were made,
673      * but notifications about subscription changes may be skipped if this returns false as an
674      * optimization to avoid spurious notifications.
675      */
676     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
updateEmbeddedSubscriptions()677     public boolean updateEmbeddedSubscriptions() {
678         // Do nothing if eUICCs are disabled. (Previous entries may remain in the cache, but they
679         // are filtered out of list calls as long as EuiccManager.isEnabled returns false).
680         if (!mEuiccManager.isEnabled()) {
681             return false;
682         }
683 
684         GetEuiccProfileInfoListResult result =
685                 EuiccController.get().blockingGetEuiccProfileInfoList();
686         if (result == null) {
687             // IPC to the eUICC controller failed.
688             return false;
689         }
690 
691         final EuiccProfileInfo[] embeddedProfiles;
692         if (result.getResult() == EuiccService.RESULT_OK) {
693             List<EuiccProfileInfo> list = result.getProfiles();
694             if (list == null || list.size() == 0) {
695                 embeddedProfiles = new EuiccProfileInfo[0];
696             } else {
697                 embeddedProfiles = list.toArray(new EuiccProfileInfo[list.size()]);
698             }
699         } else {
700             logd("updatedEmbeddedSubscriptions: error " + result.getResult() + " listing profiles");
701             // If there's an error listing profiles, treat it equivalently to a successful
702             // listing which returned no profiles under the assumption that none are currently
703             // accessible.
704             embeddedProfiles = new EuiccProfileInfo[0];
705         }
706         final boolean isRemovable = result.getIsRemovable();
707 
708         final String[] embeddedIccids = new String[embeddedProfiles.length];
709         for (int i = 0; i < embeddedProfiles.length; i++) {
710             embeddedIccids[i] = embeddedProfiles[i].getIccid();
711         }
712 
713         // Note that this only tracks whether we make any writes to the DB. It's possible this will
714         // be set to true for an update even when the row contents remain exactly unchanged from
715         // before, since we don't compare against the previous value. Since this is only intended to
716         // avoid some spurious broadcasts (particularly for users who don't use eSIM at all), this
717         // is fine.
718         boolean hasChanges = false;
719 
720         // Update or insert records for all embedded subscriptions (except non-removable ones if the
721         // current eUICC is non-removable, since we assume these are still accessible though not
722         // returned by the eUICC controller).
723         List<SubscriptionInfo> existingSubscriptions = SubscriptionController.getInstance()
724                 .getSubscriptionInfoListForEmbeddedSubscriptionUpdate(embeddedIccids, isRemovable);
725         ContentResolver contentResolver = mContext.getContentResolver();
726         for (EuiccProfileInfo embeddedProfile : embeddedProfiles) {
727             int index =
728                     findSubscriptionInfoForIccid(existingSubscriptions, embeddedProfile.getIccid());
729             if (index < 0) {
730                 // No existing entry for this ICCID; create an empty one.
731                 SubscriptionController.getInstance().insertEmptySubInfoRecord(
732                         embeddedProfile.getIccid(), SubscriptionManager.SIM_NOT_INSERTED);
733             } else {
734                 existingSubscriptions.remove(index);
735             }
736             ContentValues values = new ContentValues();
737             values.put(SubscriptionManager.IS_EMBEDDED, 1);
738             List<UiccAccessRule> ruleList = embeddedProfile.getUiccAccessRules();
739             boolean isRuleListEmpty = false;
740             if (ruleList == null || ruleList.size() == 0) {
741                 isRuleListEmpty = true;
742             }
743             values.put(SubscriptionManager.ACCESS_RULES,
744                     isRuleListEmpty ? null : UiccAccessRule.encodeRules(
745                             ruleList.toArray(new UiccAccessRule[ruleList.size()])));
746             values.put(SubscriptionManager.IS_REMOVABLE, isRemovable);
747             values.put(SubscriptionManager.DISPLAY_NAME, embeddedProfile.getNickname());
748             values.put(SubscriptionManager.NAME_SOURCE, SubscriptionManager.NAME_SOURCE_USER_INPUT);
749             hasChanges = true;
750             contentResolver.update(SubscriptionManager.CONTENT_URI, values,
751                     SubscriptionManager.ICC_ID + "=\"" + embeddedProfile.getIccid() + "\"", null);
752 
753             // refresh Cached Active Subscription Info List
754             SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
755         }
756 
757         // Remove all remaining subscriptions which have embedded = true. We set embedded to false
758         // to ensure they are not returned in the list of embedded subscriptions (but keep them
759         // around in case the subscription is added back later, which is equivalent to a removable
760         // SIM being removed and reinserted).
761         if (!existingSubscriptions.isEmpty()) {
762             List<String> iccidsToRemove = new ArrayList<>();
763             for (int i = 0; i < existingSubscriptions.size(); i++) {
764                 SubscriptionInfo info = existingSubscriptions.get(i);
765                 if (info.isEmbedded()) {
766                     iccidsToRemove.add("\"" + info.getIccId() + "\"");
767                 }
768             }
769             String whereClause = SubscriptionManager.ICC_ID + " IN ("
770                     + TextUtils.join(",", iccidsToRemove) + ")";
771             ContentValues values = new ContentValues();
772             values.put(SubscriptionManager.IS_EMBEDDED, 0);
773             hasChanges = true;
774             contentResolver.update(SubscriptionManager.CONTENT_URI, values, whereClause, null);
775 
776             // refresh Cached Active Subscription Info List
777             SubscriptionController.getInstance().refreshCachedActiveSubscriptionInfoList();
778         }
779 
780         return hasChanges;
781     }
782 
findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid)783     private static int findSubscriptionInfoForIccid(List<SubscriptionInfo> list, String iccid) {
784         for (int i = 0; i < list.size(); i++) {
785             if (TextUtils.equals(iccid, list.get(i).getIccId())) {
786                 return i;
787             }
788         }
789         return -1;
790     }
791 
isNewSim(String iccId, String decIccId, String[] oldIccId)792     private boolean isNewSim(String iccId, String decIccId, String[] oldIccId) {
793         boolean newSim = true;
794         for(int i = 0; i < PROJECT_SIM_NUM; i++) {
795             if(iccId.equals(oldIccId[i])) {
796                 newSim = false;
797                 break;
798             } else if (decIccId != null && decIccId.equals(oldIccId[i])) {
799                 newSim = false;
800                 break;
801             }
802         }
803         logd("newSim = " + newSim);
804 
805         return newSim;
806     }
807 
broadcastSimStateChanged(int slotId, String state, String reason)808     private void broadcastSimStateChanged(int slotId, String state, String reason) {
809         Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
810         // TODO - we'd like this intent to have a single snapshot of all sim state,
811         // but until then this should not use REPLACE_PENDING or we may lose
812         // information
813         // i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
814         //         | Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
815         i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
816         i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
817         i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
818         i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
819         SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId);
820         logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " + state + " reason " + reason +
821              " for mCardIndex: " + slotId);
822         IntentBroadcaster.getInstance().broadcastStickyIntent(i, slotId);
823     }
824 
broadcastSimCardStateChanged(int phoneId, int state)825     private void broadcastSimCardStateChanged(int phoneId, int state) {
826         if (state != sSimCardState[phoneId]) {
827             sSimCardState[phoneId] = state;
828             Intent i = new Intent(TelephonyManager.ACTION_SIM_CARD_STATE_CHANGED);
829             i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
830             i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
831             i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
832             SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId);
833             logd("Broadcasting intent ACTION_SIM_CARD_STATE_CHANGED " + simStateString(state)
834                     + " for phone: " + phoneId);
835             mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
836         }
837     }
838 
broadcastSimApplicationStateChanged(int phoneId, int state)839     private void broadcastSimApplicationStateChanged(int phoneId, int state) {
840         // Broadcast if the state has changed, except if old state was UNKNOWN and new is NOT_READY,
841         // because that's the initial state and a broadcast should be sent only on a transition
842         // after SIM is PRESENT
843         if (!(state == sSimApplicationState[phoneId]
844                 || (state == TelephonyManager.SIM_STATE_NOT_READY
845                 && sSimApplicationState[phoneId] == TelephonyManager.SIM_STATE_UNKNOWN))) {
846             sSimApplicationState[phoneId] = state;
847             Intent i = new Intent(TelephonyManager.ACTION_SIM_APPLICATION_STATE_CHANGED);
848             i.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
849             i.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
850             i.putExtra(TelephonyManager.EXTRA_SIM_STATE, state);
851             SubscriptionManager.putPhoneIdAndSubIdExtra(i, phoneId);
852             logd("Broadcasting intent ACTION_SIM_APPLICATION_STATE_CHANGED " + simStateString(state)
853                     + " for phone: " + phoneId);
854             mContext.sendBroadcast(i, Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
855         }
856     }
857 
simStateString(int state)858     private static String simStateString(int state) {
859         switch (state) {
860             case TelephonyManager.SIM_STATE_UNKNOWN:
861                 return "UNKNOWN";
862             case TelephonyManager.SIM_STATE_ABSENT:
863                 return "ABSENT";
864             case TelephonyManager.SIM_STATE_PIN_REQUIRED:
865                 return "PIN_REQUIRED";
866             case TelephonyManager.SIM_STATE_PUK_REQUIRED:
867                 return "PUK_REQUIRED";
868             case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
869                 return "NETWORK_LOCKED";
870             case TelephonyManager.SIM_STATE_READY:
871                 return "READY";
872             case TelephonyManager.SIM_STATE_NOT_READY:
873                 return "NOT_READY";
874             case TelephonyManager.SIM_STATE_PERM_DISABLED:
875                 return "PERM_DISABLED";
876             case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
877                 return "CARD_IO_ERROR";
878             case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
879                 return "CARD_RESTRICTED";
880             case TelephonyManager.SIM_STATE_LOADED:
881                 return "LOADED";
882             case TelephonyManager.SIM_STATE_PRESENT:
883                 return "PRESENT";
884             default:
885                 return "INVALID";
886         }
887     }
888 
logd(String message)889     private void logd(String message) {
890         Rlog.d(LOG_TAG, message);
891     }
892 
dump(FileDescriptor fd, PrintWriter pw, String[] args)893     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
894         pw.println("SubscriptionInfoUpdater:");
895         mCarrierServiceBindHelper.dump(fd, pw, args);
896     }
897 }
898