• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.internal.telephony.uicc;
18 
19 import static android.telephony.SmsManager.STATUS_ON_ICC_READ;
20 import static android.telephony.SmsManager.STATUS_ON_ICC_UNREAD;
21 
22 import android.compat.annotation.UnsupportedAppUsage;
23 import android.content.Context;
24 import android.content.res.Resources;
25 import android.os.AsyncResult;
26 import android.os.Build;
27 import android.os.Message;
28 import android.os.PersistableBundle;
29 import android.telephony.CarrierConfigManager;
30 import android.telephony.PhoneNumberUtils;
31 import android.telephony.SmsMessage;
32 import android.telephony.SubscriptionInfo;
33 import android.telephony.SubscriptionManager;
34 import android.text.TextUtils;
35 import android.util.Log;
36 import android.util.Pair;
37 
38 import com.android.internal.annotations.VisibleForTesting;
39 import com.android.internal.telephony.CommandsInterface;
40 import com.android.internal.telephony.MccTable;
41 import com.android.internal.telephony.SmsConstants;
42 import com.android.internal.telephony.gsm.SimTlv;
43 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
44 import com.android.telephony.Rlog;
45 
46 import java.io.FileDescriptor;
47 import java.io.PrintWriter;
48 import java.util.ArrayList;
49 import java.util.Arrays;
50 import java.util.List;
51 
52 /**
53  * {@hide}
54  */
55 public class SIMRecords extends IccRecords {
56     protected static final String LOG_TAG = "SIMRecords";
57 
58     private static final boolean CRASH_RIL = false;
59     private static final boolean FORCE_VERBOSE_STATE_LOGGING = false; /* stopship if true */
60     private static final boolean VDBG =  FORCE_VERBOSE_STATE_LOGGING ||
61             Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
62 
63     // ***** Instance Variables
64 
65     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
66     VoiceMailConstants mVmConfig;
67 
68     // ***** Cached SIM State; cleared on channel close
69 
70     private int mCallForwardingStatus;
71 
72     /**
73      * States only used by getSpnFsm FSM
74      */
75     private GetSpnFsmState mSpnState;
76 
77     /** CPHS service information (See CPHS 4.2 B.3.1.1)
78      *  It will be set in onSimReady if reading GET_CPHS_INFO successfully
79      *  mCphsInfo[0] is CPHS Phase
80      *  mCphsInfo[1] and mCphsInfo[2] is CPHS Service Table
81      */
82     private byte[] mCphsInfo = null;
83     boolean mCspPlmnEnabled = true;
84 
85     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
86     byte[] mEfMWIS = null;
87     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
88     byte[] mEfCPHS_MWI =null;
89     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
90     byte[] mEfCff = null;
91     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
92     byte[] mEfCfis = null;
93 
94     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
95     byte[] mEfLi = null;
96     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
97     byte[] mEfPl = null;
98 
99     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
100     UsimServiceTable mUsimServiceTable;
101 
102     @Override
toString()103     public String toString() {
104         return "SimRecords: " + super.toString()
105                 + " mVmConfig" + mVmConfig
106                 + " callForwardingEnabled=" + mCallForwardingStatus
107                 + " spnState=" + mSpnState
108                 + " mCphsInfo=" + IccUtils.bytesToHexString(mCphsInfo)
109                 + " mCspPlmnEnabled=" + mCspPlmnEnabled
110                 + " efMWIS=" + IccUtils.bytesToHexString(mEfMWIS)
111                 + " efCPHS_MWI=" + IccUtils.bytesToHexString(mEfCPHS_MWI)
112                 + " mEfCff=" + IccUtils.bytesToHexString(mEfCff)
113                 + " mEfCfis=" + IccUtils.bytesToHexString(mEfCfis)
114                 + " getOperatorNumeric=" + getOperatorNumeric()
115                 + " mPsiSmsc=" + mPsiSmsc
116                 + " TPMR=" + getSmssTpmrValue();
117     }
118 
119     // ***** Constants
120 
121     // From TS 51.011 EF[SPDI] section
122     static final int TAG_SPDI = 0xA3;
123     static final int TAG_SPDI_PLMN_LIST = 0x80;
124 
125     // Full Name IEI from TS 24.008
126     static final int TAG_FULL_NETWORK_NAME = 0x43;
127 
128     // Short Name IEI from TS 24.008
129     static final int TAG_SHORT_NETWORK_NAME = 0x45;
130 
131     // PLMN Additional Information tag from from TS 24.008
132     static final int TAG_PLMN_ADDITIONAL_INFORMATION = 0x80;
133 
134     // active CFF from CPHS 4.2 B.4.5
135     static final int CFF_UNCONDITIONAL_ACTIVE = 0x0a;
136     static final int CFF_UNCONDITIONAL_DEACTIVE = 0x05;
137     static final int CFF_LINE1_MASK = 0x0f;
138     static final int CFF_LINE1_RESET = 0xf0;
139 
140     // CPHS Service Table (See CPHS 4.2 B.3.1)
141     private static final int CPHS_SST_MBN_MASK = 0x30;
142     private static final int CPHS_SST_MBN_ENABLED = 0x30;
143 
144     // EF_CFIS related constants
145     // Spec reference TS 51.011 section 10.3.46.
146     private static final int CFIS_BCD_NUMBER_LENGTH_OFFSET = 2;
147     private static final int CFIS_TON_NPI_OFFSET = 3;
148     private static final int CFIS_ADN_CAPABILITY_ID_OFFSET = 14;
149     private static final int CFIS_ADN_EXTENSION_ID_OFFSET = 15;
150 
151     // 3GPP specification constants
152     // Spec reference TS 31.102 section 4.2.16
153     private static final int FPLMN_BYTE_SIZE = 3;
154 
155     // ***** Event Constants
156     private static final int SIM_RECORD_EVENT_BASE = 0x00;
157     private static final int EVENT_GET_IMSI_DONE = 3 + SIM_RECORD_EVENT_BASE;
158     private static final int EVENT_GET_ICCID_DONE = 4 + SIM_RECORD_EVENT_BASE;
159     private static final int EVENT_GET_MBI_DONE = 5 + SIM_RECORD_EVENT_BASE;
160     private static final int EVENT_GET_MBDN_DONE = 6 + SIM_RECORD_EVENT_BASE;
161     private static final int EVENT_GET_MWIS_DONE = 7 + SIM_RECORD_EVENT_BASE;
162     private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8 + SIM_RECORD_EVENT_BASE;
163     private static final int EVENT_GET_AD_DONE = 9 + SIM_RECORD_EVENT_BASE; // Admin data on SIM
164     private static final int EVENT_GET_MSISDN_DONE = 10 + SIM_RECORD_EVENT_BASE;
165     private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11 + SIM_RECORD_EVENT_BASE;
166     private static final int EVENT_GET_SPN_DONE = 12 + SIM_RECORD_EVENT_BASE;
167     private static final int EVENT_GET_SPDI_DONE = 13 + SIM_RECORD_EVENT_BASE;
168     private static final int EVENT_UPDATE_DONE = 14 + SIM_RECORD_EVENT_BASE;
169     protected static final int EVENT_GET_PNN_DONE = 15 + SIM_RECORD_EVENT_BASE;
170     protected static final int EVENT_GET_OPL_DONE = 16 + SIM_RECORD_EVENT_BASE;
171     protected static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE;
172     private static final int EVENT_GET_ALL_SMS_DONE = 18 + SIM_RECORD_EVENT_BASE;
173     private static final int EVENT_MARK_SMS_READ_DONE = 19 + SIM_RECORD_EVENT_BASE;
174     private static final int EVENT_SET_MBDN_DONE = 20 + SIM_RECORD_EVENT_BASE;
175     private static final int EVENT_SMS_ON_SIM = 21 + SIM_RECORD_EVENT_BASE;
176     private static final int EVENT_GET_SMS_DONE = 22 + SIM_RECORD_EVENT_BASE;
177     private static final int EVENT_GET_CFF_DONE = 24 + SIM_RECORD_EVENT_BASE;
178     private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25 + SIM_RECORD_EVENT_BASE;
179     private static final int EVENT_GET_INFO_CPHS_DONE = 26 + SIM_RECORD_EVENT_BASE;
180     private static final int EVENT_SET_MSISDN_DONE = 30 + SIM_RECORD_EVENT_BASE;
181     private static final int EVENT_GET_CFIS_DONE = 32 + SIM_RECORD_EVENT_BASE;
182     private static final int EVENT_GET_CSP_CPHS_DONE = 33 + SIM_RECORD_EVENT_BASE;
183     private static final int EVENT_GET_GID1_DONE = 34 + SIM_RECORD_EVENT_BASE;
184     private static final int EVENT_GET_GID2_DONE = 36 + SIM_RECORD_EVENT_BASE;
185     private static final int EVENT_GET_PLMN_W_ACT_DONE = 37 + SIM_RECORD_EVENT_BASE;
186     private static final int EVENT_GET_OPLMN_W_ACT_DONE = 38 + SIM_RECORD_EVENT_BASE;
187     private static final int EVENT_GET_HPLMN_W_ACT_DONE = 39 + SIM_RECORD_EVENT_BASE;
188     private static final int EVENT_GET_EHPLMN_DONE = 40 + SIM_RECORD_EVENT_BASE;
189     private static final int EVENT_GET_FPLMN_DONE = 41 + SIM_RECORD_EVENT_BASE;
190     private static final int EVENT_GET_FPLMN_SIZE_DONE = 42 + SIM_RECORD_EVENT_BASE;
191     private static final int EVENT_SET_FPLMN_DONE = 43 + SIM_RECORD_EVENT_BASE;
192     protected static final int EVENT_GET_SMSS_RECORD_DONE = 46 + SIM_RECORD_EVENT_BASE;
193     protected static final int EVENT_GET_PSISMSC_DONE = 47 + SIM_RECORD_EVENT_BASE;
194 
195     // ***** Constructor
196 
SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci)197     public SIMRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
198         super(app, c, ci);
199 
200         mAdnCache = new AdnRecordCache(mFh);
201 
202         mVmConfig = new VoiceMailConstants();
203 
204         mRecordsRequested = false;  // No load request is made till SIM ready
205         mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
206 
207         // recordsToLoad is set to 0 because no requests are made yet
208         mRecordsToLoad = 0;
209 
210         mCi.setOnSmsOnSim(this, EVENT_SMS_ON_SIM, null);
211 
212         // Start off by setting empty state
213         resetRecords();
214         if (DBG) log("SIMRecords X ctor this=" + this);
215     }
216 
217     @Override
dispose()218     public void dispose() {
219         if (DBG) log("Disposing SIMRecords this=" + this);
220         //Unregister for all events
221         mCi.unSetOnSmsOnSim(this);
222         resetRecords();
223         super.dispose();
224     }
225 
226     @Override
finalize()227     protected void finalize() {
228         if (DBG) log("finalized");
229     }
230 
resetRecords()231     protected void resetRecords() {
232         mImsi = null;
233         mMsisdn = null;
234         mVoiceMailNum = null;
235         mMncLength = UNINITIALIZED;
236         log("setting0 mMncLength" + mMncLength);
237         mIccId = null;
238         mFullIccId = null;
239         mCarrierNameDisplayCondition = DEFAULT_CARRIER_NAME_DISPLAY_CONDITION;
240         mEfMWIS = null;
241         mEfCPHS_MWI = null;
242         mSpdi = null;
243         mPnnHomeName = null;
244         mPnns = null;
245         mOpl = null;
246         mGid1 = null;
247         mGid2 = null;
248         mPlmnActRecords = null;
249         mOplmnActRecords = null;
250         mHplmnActRecords = null;
251         mFplmns = null;
252         mEhplmns = null;
253 
254         mAdnCache.reset();
255 
256         log("SIMRecords: onRadioOffOrNotAvailable set 'gsm.sim.operator.numeric' to operator=null");
257         log("update icc_operator_numeric=" + null);
258         mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), "");
259         mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), "");
260         mTelephonyManager.setSimCountryIsoForPhone(mParentApp.getPhoneId(), "");
261 
262         // recordsRequested is set to false indicating that the SIM
263         // read requests made so far are not valid. This is set to
264         // true only when fresh set of read requests are made.
265         mRecordsRequested = false;
266         mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
267         mLoaded.set(false);
268     }
269 
270     //***** Public Methods
271 
272     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
273     @Override
getMsisdnNumber()274     public String getMsisdnNumber() {
275         return mMsisdn;
276     }
277 
278     @Override
getUsimServiceTable()279     public UsimServiceTable getUsimServiceTable() {
280         return mUsimServiceTable;
281     }
282 
283     /**
284      * Fetches the USIM service table from UsimServiceTable
285      *
286      * @return HexString representation of USIM service table
287      */
getSimServiceTable()288     public String getSimServiceTable() {
289         if (mUsimServiceTable != null) {
290             return IccUtils.bytesToHexString(mUsimServiceTable.getUSIMServiceTable());
291         }
292         return null;
293     }
294 
295     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getExtFromEf(int ef)296     private int getExtFromEf(int ef) {
297         int ext;
298         switch (ef) {
299             case EF_FDN: return EF_EXT2;
300             case EF_MSISDN:
301                 /* For USIM apps use EXT5. (TS 31.102 Section 4.2.37) */
302                 if (mParentApp.getType() == AppType.APPTYPE_USIM) {
303                     ext = EF_EXT5;
304                 } else {
305                     ext = EF_EXT1;
306                 }
307                 break;
308             default:
309                 ext = EF_EXT1;
310         }
311         return ext;
312     }
313 
314     /**
315      * Set subscriber number to SIM record
316      *
317      * The subscriber number is stored in EF_MSISDN (TS 51.011)
318      *
319      * When the operation is complete, onComplete will be sent to its handler
320      *
321      * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters)
322      * @param number dialing number (up to 20 digits)
323      *        if the number starts with '+', then set to international TOA
324      * @param onComplete
325      *        onComplete.obj will be an AsyncResult
326      *        ((AsyncResult)onComplete.obj).exception == null on success
327      *        ((AsyncResult)onComplete.obj).exception != null on fail
328      */
329     @Override
setMsisdnNumber(String alphaTag, String number, Message onComplete)330     public void setMsisdnNumber(String alphaTag, String number,
331             Message onComplete) {
332         if (mDestroyed.get()) {
333             return;
334         }
335         // If the SIM card is locked by PIN, we will set EF_MSISDN fail.
336         // In that case, msisdn and msisdnTag should not be update.
337         mNewMsisdn = number;
338         mNewMsisdnTag = alphaTag;
339 
340         if(DBG) log("Set MSISDN: " + mNewMsisdnTag + " " + /*mNewMsisdn*/
341                 Rlog.pii(LOG_TAG, mNewMsisdn));
342 
343         AdnRecord adn = new AdnRecord(mNewMsisdnTag, mNewMsisdn);
344 
345         new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, getExtFromEf(EF_MSISDN), 1, null,
346                 obtainMessage(EVENT_SET_MSISDN_DONE, onComplete));
347     }
348 
349     @Override
getMsisdnAlphaTag()350     public String getMsisdnAlphaTag() {
351         return mMsisdnTag;
352     }
353 
354     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
355     @Override
getVoiceMailNumber()356     public String getVoiceMailNumber() {
357         return mVoiceMailNum;
358     }
359 
360     /**
361      * Set voice mail number to SIM record
362      *
363      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
364      * EF_MAILBOX_CPHS (CPHS 4.2)
365      *
366      * If EF_MBDN is available, store the voice mail number to EF_MBDN
367      *
368      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
369      *
370      * So the voice mail number will be stored in both EFs if both are available
371      *
372      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
373      *
374      * When the operation is complete, onComplete will be sent to its handler
375      *
376      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
377      * @param voiceNumber dailing nubmer (upto 20 digits)
378      *        if the number is start with '+', then set to international TOA
379      * @param onComplete
380      *        onComplete.obj will be an AsyncResult
381      *        ((AsyncResult)onComplete.obj).exception == null on success
382      *        ((AsyncResult)onComplete.obj).exception != null on fail
383      */
384     @Override
setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete)385     public void setVoiceMailNumber(String alphaTag, String voiceNumber,
386             Message onComplete) {
387         if (mDestroyed.get()) {
388             return;
389         }
390 
391         if (mIsVoiceMailFixed) {
392             AsyncResult.forMessage((onComplete)).exception =
393                     new IccVmFixedException("Voicemail number is fixed by operator");
394             onComplete.sendToTarget();
395             return;
396         }
397 
398         mNewVoiceMailNum = voiceNumber;
399         mNewVoiceMailTag = alphaTag;
400 
401         AdnRecord adn = new AdnRecord(mNewVoiceMailTag, mNewVoiceMailNum);
402         if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
403 
404             new AdnRecordLoader(mFh).updateEF(adn, EF_MBDN, EF_EXT6,
405                     mMailboxIndex, null,
406                     obtainMessage(EVENT_SET_MBDN_DONE, AdnRecordLoader.VOICEMAIL_ALPHATAG_ARG,
407                             0 /* ignored arg2 */, onComplete));
408 
409         } else if (isCphsMailboxEnabled()) {
410 
411             new AdnRecordLoader(mFh).updateEF(adn, EF_MAILBOX_CPHS,
412                     EF_EXT1, 1, null,
413                     obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
414                             AdnRecordLoader.VOICEMAIL_ALPHATAG_ARG,
415                             0 /* ignored arg2 */, onComplete));
416 
417         } else {
418             AsyncResult.forMessage((onComplete)).exception =
419                     new IccVmNotSupportedException("Update SIM voice mailbox error");
420             onComplete.sendToTarget();
421         }
422     }
423 
424     @Override
getVoiceMailAlphaTag()425     public String getVoiceMailAlphaTag()
426     {
427         return mVoiceMailTag;
428     }
429 
430     /**
431      * Sets the SIM voice message waiting indicator records
432      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
433      * @param countWaiting The number of messages waiting, if known. Use
434      *                     -1 to indicate that an unknown number of
435      *                      messages are waiting
436      */
437     @Override
438     public void
setVoiceMessageWaiting(int line, int countWaiting)439     setVoiceMessageWaiting(int line, int countWaiting) {
440         if (mDestroyed.get()) {
441             return;
442         }
443         if (line != 1) {
444             // only profile 1 is supported
445             return;
446         }
447 
448         try {
449             if (mEfMWIS != null) {
450                 // TS 51.011 10.3.45
451 
452                 // lsb of byte 0 is 'voicemail' status
453                 mEfMWIS[0] = (byte)((mEfMWIS[0] & 0xfe)
454                                     | (countWaiting == 0 ? 0 : 1));
455 
456                 // byte 1 is the number of voice messages waiting
457                 if (countWaiting < 0) {
458                     // The spec does not define what this should be
459                     // if we don't know the count
460                     mEfMWIS[1] = 0;
461                 } else {
462                     mEfMWIS[1] = (byte) countWaiting;
463                 }
464 
465                 mFh.updateEFLinearFixed(
466                     EF_MWIS, 1, mEfMWIS, null,
467                     obtainMessage (EVENT_UPDATE_DONE, EF_MWIS, 0));
468             }
469 
470             if (mEfCPHS_MWI != null) {
471                     // Refer CPHS4_2.WW6 B4.2.3
472                 mEfCPHS_MWI[0] = (byte)((mEfCPHS_MWI[0] & 0xf0)
473                             | (countWaiting == 0 ? 0x5 : 0xa));
474                 mFh.updateEFTransparent(
475                     EF_VOICE_MAIL_INDICATOR_CPHS, mEfCPHS_MWI,
476                     obtainMessage (EVENT_UPDATE_DONE, EF_VOICE_MAIL_INDICATOR_CPHS));
477             }
478         } catch (ArrayIndexOutOfBoundsException ex) {
479             logw("Error saving voice mail state to SIM. Probably malformed SIM record", ex);
480         }
481     }
482 
483     // Validate data is not null and not empty.
validEfCfis(byte[] data)484     private boolean validEfCfis(byte[] data) {
485         if (data != null) {
486             if (data[0] < 1 || data[0] > 4) {
487                 // The MSP (Multiple Subscriber Profile) byte should be between
488                 // 1 and 4 according to ETSI TS 131 102 v11.3.0 section 4.2.64.
489                 logw("MSP byte: " + data[0] + " is not between 1 and 4", null);
490             }
491             // empty EF_CFIS should be considered as call forward disabled
492             for (byte b : data) {
493                 if (b != (byte) 0xFF) {
494                     return true;
495                 }
496             }
497         }
498         return false;
499     }
500 
getVoiceMessageCount()501     public int getVoiceMessageCount() {
502         boolean voiceMailWaiting = false;
503         int countVoiceMessages = DEFAULT_VOICE_MESSAGE_COUNT;
504         if (mEfMWIS != null) {
505             // Use this data if the EF[MWIS] exists and
506             // has been loaded
507             // Refer TS 51.011 Section 10.3.45 for the content description
508             voiceMailWaiting = ((mEfMWIS[0] & 0x01) != 0);
509             countVoiceMessages = mEfMWIS[1] & 0xff;
510 
511             if (voiceMailWaiting && (countVoiceMessages == 0 || countVoiceMessages == 0xff)) {
512                 // Unknown count = -1
513                 countVoiceMessages = UNKNOWN_VOICE_MESSAGE_COUNT;
514             }
515             if (DBG) log(" VoiceMessageCount from SIM MWIS = " + countVoiceMessages);
516         } else if (mEfCPHS_MWI != null) {
517             // use voice mail count from CPHS
518             int indicator = (int) (mEfCPHS_MWI[0] & 0xf);
519 
520             // Refer CPHS4_2.WW6 B4.2.3
521             if (indicator == 0xA) {
522                 // Unknown count = -1
523                 countVoiceMessages = UNKNOWN_VOICE_MESSAGE_COUNT;
524             } else if (indicator == 0x5) {
525                 countVoiceMessages = 0;
526             }
527             if (DBG) log(" VoiceMessageCount from SIM CPHS = " + countVoiceMessages);
528         }
529         return countVoiceMessages;
530     }
531 
532     /**
533      * {@inheritDoc}
534      */
535     @Override
getVoiceCallForwardingFlag()536     public int getVoiceCallForwardingFlag() {
537         return mCallForwardingStatus;
538     }
539 
540     /**
541      * {@inheritDoc}
542      */
543     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
544     @Override
setVoiceCallForwardingFlag(int line, boolean enable, String dialNumber)545     public void setVoiceCallForwardingFlag(int line, boolean enable, String dialNumber) {
546         if (mDestroyed.get()) {
547             return;
548         }
549         if (line != 1) return; // only line 1 is supported
550 
551         mCallForwardingStatus = enable ? CALL_FORWARDING_STATUS_ENABLED :
552                 CALL_FORWARDING_STATUS_DISABLED;
553 
554         mRecordsEventsRegistrants.notifyResult(EVENT_CFI);
555 
556         try {
557             if (validEfCfis(mEfCfis)) {
558                 // lsb is of byte f1 is voice status
559                 if (enable) {
560                     mEfCfis[1] |= 1;
561                 } else {
562                     mEfCfis[1] &= 0xfe;
563                 }
564 
565                 log("setVoiceCallForwardingFlag: enable=" + enable
566                         + " mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
567 
568                 // Update dialNumber if not empty and CFU is enabled.
569                 // Spec reference for EF_CFIS contents, TS 51.011 section 10.3.46.
570                 if (enable && !TextUtils.isEmpty(dialNumber)) {
571                     logv("EF_CFIS: updating cf number, " + Rlog.pii(LOG_TAG, dialNumber));
572                     byte[] bcdNumber = PhoneNumberUtils.numberToCalledPartyBCD(
573                             dialNumber, PhoneNumberUtils.BCD_EXTENDED_TYPE_EF_ADN);
574 
575                     System.arraycopy(bcdNumber, 0, mEfCfis, CFIS_TON_NPI_OFFSET, bcdNumber.length);
576 
577                     mEfCfis[CFIS_BCD_NUMBER_LENGTH_OFFSET] = (byte) (bcdNumber.length);
578                     mEfCfis[CFIS_ADN_CAPABILITY_ID_OFFSET] = (byte) 0xFF;
579                     mEfCfis[CFIS_ADN_EXTENSION_ID_OFFSET] = (byte) 0xFF;
580                 }
581 
582                 mFh.updateEFLinearFixed(
583                         EF_CFIS, 1, mEfCfis, null,
584                         obtainMessage (EVENT_UPDATE_DONE, EF_CFIS));
585             } else {
586                 log("setVoiceCallForwardingFlag: ignoring enable=" + enable
587                         + " invalid mEfCfis=" + IccUtils.bytesToHexString(mEfCfis));
588             }
589 
590             if (mEfCff != null) {
591                 if (enable) {
592                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
593                             | CFF_UNCONDITIONAL_ACTIVE);
594                 } else {
595                     mEfCff[0] = (byte) ((mEfCff[0] & CFF_LINE1_RESET)
596                             | CFF_UNCONDITIONAL_DEACTIVE);
597                 }
598 
599                 mFh.updateEFTransparent(
600                         EF_CFF_CPHS, mEfCff,
601                         obtainMessage (EVENT_UPDATE_DONE, EF_CFF_CPHS));
602             }
603         } catch (ArrayIndexOutOfBoundsException ex) {
604             logw("Error saving call forwarding flag to SIM. "
605                             + "Probably malformed SIM record", ex);
606 
607         }
608     }
609 
610     /**
611      * Called by STK Service when REFRESH is received.
612      * @param fileChanged indicates whether any files changed
613      * @param fileList if non-null, a list of EF files that changed
614      */
615     @Override
onRefresh(boolean fileChanged, int[] fileList)616     public void onRefresh(boolean fileChanged, int[] fileList) {
617         if (fileChanged) {
618             // A future optimization would be to inspect fileList and
619             // only reload those files that we care about.  For now,
620             // just re-fetch all SIM records that we cache.
621             fetchSimRecords();
622         }
623     }
624 
625     /**
626      * {@inheritDoc}
627      */
628     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
629     @Override
getOperatorNumeric()630     public String getOperatorNumeric() {
631         String imsi = getIMSI();
632         if (imsi == null) {
633             log("getOperatorNumeric: IMSI == null");
634             return null;
635         }
636         if (mMncLength == UNINITIALIZED || mMncLength == UNKNOWN) {
637             log("getSIMOperatorNumeric: bad mncLength");
638             return null;
639         }
640 
641         // Length = length of MCC + length of MNC
642         // length of mcc = 3 (TS 23.003 Section 2.2)
643         if (imsi.length() >= 3 + mMncLength) {
644             return imsi.substring(0, 3 + mMncLength);
645         } else {
646             return null;
647         }
648     }
649 
650     // ***** Overridden from Handler
651     @Override
handleMessage(Message msg)652     public void handleMessage(Message msg) {
653         AsyncResult ar;
654         AdnRecord adn;
655 
656         byte data[];
657 
658         boolean isRecordLoadResponse = false;
659 
660         if (mDestroyed.get()) {
661             loge("Received message " + msg + "[" + msg.what + "] " +
662                     " while being destroyed. Ignoring.");
663             return;
664         }
665         try {
666             switch (msg.what) {
667                 /* IO events */
668                 case EVENT_GET_IMSI_DONE:
669                     isRecordLoadResponse = true;
670                     ar = (AsyncResult) msg.obj;
671 
672                     if (ar.exception != null) {
673                         loge("Exception querying IMSI, Exception:" + ar.exception);
674                         break;
675                     }
676 
677                     setImsi((String) ar.result);
678                     break;
679 
680                 case EVENT_GET_MBI_DONE:
681                     boolean isValidMbdn;
682                     isRecordLoadResponse = true;
683 
684                     ar = (AsyncResult) msg.obj;
685                     data = (byte[]) ar.result;
686 
687                     isValidMbdn = false;
688                     if (ar.exception == null) {
689                         // Refer TS 51.011 Section 10.3.44 for content details
690                         log("EF_MBI: " + IccUtils.bytesToHexString(data));
691 
692                         // Voice mail record number stored first
693                         mMailboxIndex = data[0] & 0xff;
694 
695                         // check if dailing numbe id valid
696                         if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
697                             log("Got valid mailbox number for MBDN");
698                             isValidMbdn = true;
699                         }
700                     }
701 
702                     // one more record to load
703                     mRecordsToLoad += 1;
704 
705                     if (isValidMbdn) {
706                         // Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
707                         new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
708                                 mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
709                     } else {
710                         // If this EF not present, try mailbox as in CPHS standard
711                         // CPHS (CPHS4_2.WW6) is a european standard.
712                         new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS,
713                                 EF_EXT1, 1,
714                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
715                     }
716 
717                     break;
718                 case EVENT_GET_CPHS_MAILBOX_DONE:
719                 case EVENT_GET_MBDN_DONE:
720                     //Resetting the voice mail number and voice mail tag to null
721                     //as these should be updated from the data read from EF_MBDN.
722                     //If they are not reset, incase of invalid data/exception these
723                     //variables are retaining their previous values and are
724                     //causing invalid voice mailbox info display to user.
725                     mVoiceMailNum = null;
726                     mVoiceMailTag = null;
727                     isRecordLoadResponse = true;
728 
729                     ar = (AsyncResult) msg.obj;
730 
731                     if (ar.exception != null) {
732 
733                         log("Invalid or missing EF"
734                                 + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE)
735                                     ? "[MAILBOX]" : "[MBDN]"));
736 
737                         // Bug #645770 fall back to CPHS
738                         // FIXME should use SST to decide
739 
740                         if (msg.what == EVENT_GET_MBDN_DONE) {
741                             //load CPHS on fail...
742                             // FIXME right now, only load line1's CPHS voice mail entry
743 
744                             mRecordsToLoad += 1;
745                             new AdnRecordLoader(mFh).loadFromEF(
746                                     EF_MAILBOX_CPHS, EF_EXT1, 1,
747                                     obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
748                         }
749                         break;
750                     }
751 
752                     adn = (AdnRecord) ar.result;
753 
754                     log("VM: " + adn
755                             + ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE)
756                                 ? " EF[MAILBOX]" : " EF[MBDN]"));
757 
758                     if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
759                         // Bug #645770 fall back to CPHS
760                         // FIXME should use SST to decide
761                         // FIXME right now, only load line1's CPHS voice mail entry
762                         mRecordsToLoad += 1;
763                         new AdnRecordLoader(mFh).loadFromEF(
764                                 EF_MAILBOX_CPHS, EF_EXT1, 1,
765                                 obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
766 
767                         break;
768                     }
769 
770                     mVoiceMailNum = adn.getNumber();
771                     mVoiceMailTag = adn.getAlphaTag();
772                     break;
773 
774                 case EVENT_GET_MSISDN_DONE:
775                     isRecordLoadResponse = true;
776 
777                     ar = (AsyncResult) msg.obj;
778 
779                     if (ar.exception != null) {
780                         log("Invalid or missing EF[MSISDN]");
781                         break;
782                     }
783 
784                     adn = (AdnRecord) ar.result;
785 
786                     mMsisdn = adn.getNumber();
787                     mMsisdnTag = adn.getAlphaTag();
788 
789                     log("MSISDN: " + /*mMsisdn*/ Rlog.pii(LOG_TAG, mMsisdn));
790                     break;
791 
792                 case EVENT_SET_MSISDN_DONE:
793                     isRecordLoadResponse = false;
794                     ar = (AsyncResult) msg.obj;
795 
796                     if (ar.exception == null) {
797                         mMsisdn = mNewMsisdn;
798                         mMsisdnTag = mNewMsisdnTag;
799                         log("Success to update EF[MSISDN]");
800                     }
801 
802                     if (ar.userObj != null) {
803                         AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception;
804                         ((Message) ar.userObj).sendToTarget();
805                     }
806                     break;
807 
808                 case EVENT_GET_MWIS_DONE:
809                     isRecordLoadResponse = true;
810 
811                     ar = (AsyncResult) msg.obj;
812                     data = (byte[]) ar.result;
813 
814                     if (DBG) log("EF_MWIS : " + IccUtils.bytesToHexString(data));
815 
816                     if (ar.exception != null) {
817                         if (DBG) log("EVENT_GET_MWIS_DONE exception = " + ar.exception);
818                         break;
819                     }
820 
821                     if ((data[0] & 0xff) == 0xff) {
822                         if (DBG) log("SIMRecords: Uninitialized record MWIS");
823                         break;
824                     }
825 
826                     mEfMWIS = data;
827                     break;
828 
829                 case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
830                     isRecordLoadResponse = true;
831 
832                     ar = (AsyncResult) msg.obj;
833                     data = (byte[]) ar.result;
834 
835                     if (DBG) log("EF_CPHS_MWI: " + IccUtils.bytesToHexString(data));
836 
837                     if (ar.exception != null) {
838                         if (DBG) {
839                             log("EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE exception = "
840                                     + ar.exception);
841                         }
842                         break;
843                     }
844 
845                     mEfCPHS_MWI = data;
846                     break;
847 
848                 case EVENT_GET_ICCID_DONE:
849                     isRecordLoadResponse = true;
850 
851                     ar = (AsyncResult) msg.obj;
852                     data = (byte[]) ar.result;
853 
854                     if (ar.exception != null) {
855                         break;
856                     }
857 
858                     mIccId = IccUtils.bcdToString(data, 0, data.length);
859                     mFullIccId = IccUtils.bchToString(data, 0, data.length);
860 
861                     log("iccid: " + SubscriptionInfo.getPrintableId(mFullIccId));
862                     break;
863 
864                 case EVENT_GET_AD_DONE:
865                     isRecordLoadResponse = true;
866                     mMncLength = UNKNOWN;
867                     try {
868                         if (!mCarrierTestOverride.isInTestMode()) {
869                             ar = (AsyncResult) msg.obj;
870                             data = (byte[]) ar.result;
871 
872                             if (ar.exception != null) {
873                                 break;
874                             }
875 
876                             log("EF_AD: " + IccUtils.bytesToHexString(data));
877 
878                             if (data.length < 3) {
879                                 log("Corrupt AD data on SIM");
880                                 break;
881                             }
882 
883                             if (data.length == 3) {
884                                 log("MNC length not present in EF_AD");
885                                 break;
886                             }
887 
888                             int len = data[3] & 0xf;
889                             if (len == 2 || len == 3) {
890                                 mMncLength = len;
891                             } else {
892                                 log("Received invalid or unset MNC Length=" + len);
893                             }
894                         }
895                     } finally {
896                         updateOperatorPlmn();
897                     }
898                     break;
899 
900                 case EVENT_GET_SPN_DONE:
901                     isRecordLoadResponse = true;
902                     ar = (AsyncResult) msg.obj;
903                     getSpnFsm(false, ar);
904                     break;
905 
906                 case EVENT_GET_CFF_DONE:
907                     isRecordLoadResponse = true;
908 
909                     ar = (AsyncResult) msg.obj;
910                     data = (byte[]) ar.result;
911 
912                     if (ar.exception != null) {
913                         mEfCff = null;
914                     } else {
915                         log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data));
916                         mEfCff = data;
917                     }
918 
919                     break;
920 
921                 case EVENT_GET_SPDI_DONE:
922                     isRecordLoadResponse = true;
923 
924                     ar = (AsyncResult) msg.obj;
925                     data = (byte[]) ar.result;
926 
927                     if (ar.exception != null) {
928                         break;
929                     }
930 
931                     parseEfSpdi(data);
932                     break;
933 
934                 case EVENT_UPDATE_DONE:
935                     ar = (AsyncResult) msg.obj;
936                     if (ar.exception != null) {
937                         logw("update failed. ", ar.exception);
938                     }
939                     break;
940 
941                 case EVENT_GET_PNN_DONE:
942                     isRecordLoadResponse = true;
943 
944                     ar = (AsyncResult) msg.obj;
945                     if (ar.exception != null) {
946                         break;
947                     }
948 
949                     parseEfPnn((ArrayList<byte[]>) ar.result);
950                     break;
951 
952                 case EVENT_GET_OPL_DONE:
953                     isRecordLoadResponse = true;
954 
955                     ar = (AsyncResult) msg.obj;
956                     if (ar.exception != null) {
957                         break;
958                     }
959 
960                     parseEfOpl((ArrayList<byte[]>) ar.result);
961                     break;
962 
963                 case EVENT_GET_ALL_SMS_DONE:
964                     isRecordLoadResponse = true;
965 
966                     ar = (AsyncResult) msg.obj;
967                     if (ar.exception != null) {
968                         break;
969                     }
970 
971                     handleSmses((ArrayList<byte[]>) ar.result);
972                     break;
973 
974                 case EVENT_MARK_SMS_READ_DONE:
975                     log("marked read: sms " + msg.arg1);
976                     break;
977 
978 
979                 case EVENT_SMS_ON_SIM:
980                     isRecordLoadResponse = false;
981 
982                     ar = (AsyncResult) msg.obj;
983 
984                     Integer index = (Integer) ar.result;
985 
986                     if (ar.exception != null || index == null) {
987                         loge("Error on SMS_ON_SIM with exp "
988                                 + ar.exception + " index " + index);
989                     } else {
990                         log("READ EF_SMS RECORD index=" + index);
991                         mFh.loadEFLinearFixed(EF_SMS, index, obtainMessage(EVENT_GET_SMS_DONE));
992                     }
993                     break;
994 
995                 case EVENT_GET_SMS_DONE:
996                     isRecordLoadResponse = false;
997                     ar = (AsyncResult) msg.obj;
998                     if (ar.exception == null) {
999                         handleSms((byte[]) ar.result);
1000                     } else {
1001                         loge("Error on GET_SMS with exp " + ar.exception);
1002                     }
1003                     break;
1004                 case EVENT_GET_SST_DONE:
1005                     isRecordLoadResponse = true;
1006 
1007                     ar = (AsyncResult) msg.obj;
1008                     data = (byte[]) ar.result;
1009 
1010                     if (ar.exception != null) {
1011                         break;
1012                     }
1013 
1014                     mUsimServiceTable = new UsimServiceTable(data);
1015                     if (DBG) log("SST: " + mUsimServiceTable);
1016                     break;
1017 
1018                 case EVENT_GET_INFO_CPHS_DONE:
1019                     isRecordLoadResponse = true;
1020 
1021                     ar = (AsyncResult) msg.obj;
1022 
1023                     if (ar.exception != null) {
1024                         break;
1025                     }
1026 
1027                     mCphsInfo = (byte[]) ar.result;
1028 
1029                     if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
1030                     break;
1031 
1032                 case EVENT_SET_MBDN_DONE:
1033                     isRecordLoadResponse = false;
1034                     ar = (AsyncResult) msg.obj;
1035 
1036                     if (DBG) log("EVENT_SET_MBDN_DONE ex:" + ar.exception);
1037                     if (ar.exception == null) {
1038                         /**
1039                          * Check for any changes made to voicemail alphaTag while saving to SIM.
1040                          * if voicemail alphaTag length is more than allowed limit of SIM EF then
1041                          * null alphaTag will be saved to SIM {@code AdnRecordLoader}.
1042                          */
1043                         if (ar.result != null) {
1044                             AdnRecord adnRecord = (AdnRecord) (ar.result);
1045                             if (adnRecord != null) {
1046                                 mNewVoiceMailTag = adnRecord.mAlphaTag;
1047                             }
1048                         }
1049                         mVoiceMailNum = mNewVoiceMailNum;
1050                         mVoiceMailTag = mNewVoiceMailTag;
1051                     }
1052                     if (isCphsMailboxEnabled()) {
1053                         adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum);
1054                         Message onCphsCompleted = (Message) ar.userObj;
1055 
1056                         /* write to cphs mailbox whenever it is available but
1057                         * we only need notify caller once if both updating are
1058                         * successful.
1059                         *
1060                         * so if set_mbdn successful, notify caller here and set
1061                         * onCphsCompleted to null
1062                         */
1063                         if (ar.exception == null && ar.userObj != null) {
1064                             AsyncResult.forMessage(((Message) ar.userObj)).exception = null;
1065                             ((Message) ar.userObj).sendToTarget();
1066 
1067                             if (DBG) log("Callback with MBDN successful.");
1068 
1069                             onCphsCompleted = null;
1070                         }
1071 
1072                         new AdnRecordLoader(mFh)
1073                                 .updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
1074                                 obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
1075                                        AdnRecordLoader.VOICEMAIL_ALPHATAG_ARG,
1076                                         0 /* ignored arg2 */, onCphsCompleted));
1077                     } else {
1078                         if (ar.userObj != null) {
1079                             CarrierConfigManager configManager = (CarrierConfigManager)
1080                                     mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
1081                             if (ar.exception != null && configManager != null) {
1082                                 PersistableBundle b = configManager.getConfigForSubId(
1083                                         SubscriptionManager.getSubscriptionId(
1084                                                 mParentApp.getPhoneId()));
1085                                 if (b != null && b.getBoolean(
1086                                         CarrierConfigManager.KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL)) {
1087                                     // GsmCdmaPhone will store vm number on device
1088                                     // when IccVmNotSupportedException occurred
1089                                     AsyncResult.forMessage(((Message) ar.userObj)).exception =
1090                                             new IccVmNotSupportedException(
1091                                                     "Update SIM voice mailbox error");
1092                                 } else {
1093                                     AsyncResult.forMessage(((Message) ar.userObj))
1094                                             .exception = ar.exception;
1095                                 }
1096                             } else {
1097                                 AsyncResult.forMessage(((Message) ar.userObj))
1098                                     .exception = ar.exception;
1099                             }
1100                             ((Message) ar.userObj).sendToTarget();
1101                         }
1102                     }
1103                     break;
1104                 case EVENT_SET_CPHS_MAILBOX_DONE:
1105                     isRecordLoadResponse = false;
1106                     ar = (AsyncResult) msg.obj;
1107                     if (ar.exception == null) {
1108                         if (ar.result != null) {
1109                             AdnRecord adnRecord = (AdnRecord) (ar.result);
1110                             if (adnRecord != null) {
1111                                 mNewVoiceMailTag = adnRecord.mAlphaTag;
1112                             }
1113                         }
1114                         mVoiceMailNum = mNewVoiceMailNum;
1115                         mVoiceMailTag = mNewVoiceMailTag;
1116                     } else {
1117                         if (DBG) log("Set CPHS MailBox with exception: " + ar.exception);
1118                     }
1119                     if (ar.userObj != null) {
1120                         if (DBG) log("Callback with CPHS MB successful.");
1121                         AsyncResult.forMessage(((Message) ar.userObj)).exception
1122                                 = ar.exception;
1123                         ((Message) ar.userObj).sendToTarget();
1124                     }
1125                     break;
1126                 case EVENT_GET_CFIS_DONE:
1127                     isRecordLoadResponse = true;
1128 
1129                     ar = (AsyncResult) msg.obj;
1130                     data = (byte[]) ar.result;
1131 
1132                     if (ar.exception != null) {
1133                         mEfCfis = null;
1134                     } else {
1135                         log("EF_CFIS: " + IccUtils.bytesToHexString(data));
1136                         mEfCfis = data;
1137                     }
1138 
1139                     break;
1140 
1141                 case EVENT_GET_CSP_CPHS_DONE:
1142                     isRecordLoadResponse = true;
1143 
1144                     ar = (AsyncResult) msg.obj;
1145 
1146                     if (ar.exception != null) {
1147                         loge("Exception in fetching EF_CSP data " + ar.exception);
1148                         break;
1149                     }
1150 
1151                     data = (byte[]) ar.result;
1152 
1153                     log("EF_CSP: " + IccUtils.bytesToHexString(data));
1154                     handleEfCspData(data);
1155                     break;
1156 
1157                 case EVENT_GET_GID1_DONE:
1158                     isRecordLoadResponse = true;
1159 
1160                     ar = (AsyncResult) msg.obj;
1161                     data = (byte[]) ar.result;
1162 
1163                     if (ar.exception != null) {
1164                         loge("Exception in get GID1 " + ar.exception);
1165                         mGid1 = null;
1166                         break;
1167                     }
1168 
1169                     mGid1 = IccUtils.bytesToHexString(data);
1170 
1171                     log("GID1: " + mGid1);
1172 
1173                     break;
1174 
1175                 case EVENT_GET_GID2_DONE:
1176                     isRecordLoadResponse = true;
1177                     ar = (AsyncResult) msg.obj;
1178                     data = (byte[]) ar.result;
1179 
1180                     if (ar.exception != null) {
1181                         loge("Exception in get GID2 " + ar.exception);
1182                         mGid2 = null;
1183                         break;
1184                     }
1185 
1186                     mGid2 = IccUtils.bytesToHexString(data);
1187 
1188                     log("GID2: " + mGid2);
1189 
1190                     break;
1191 
1192                 case EVENT_GET_PLMN_W_ACT_DONE:
1193                     isRecordLoadResponse = true;
1194                     ar = (AsyncResult) msg.obj;
1195                     data = (byte[]) ar.result;
1196 
1197                     if (ar.exception != null || data == null) {
1198                         loge("Failed getting User PLMN with Access Tech Records: " + ar.exception);
1199                         break;
1200                     } else {
1201                         log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
1202                         mPlmnActRecords = PlmnActRecord.getRecords(data);
1203                         if (VDBG) log("PlmnActRecords=" + Arrays.toString(mPlmnActRecords));
1204                     }
1205                     break;
1206 
1207                 case EVENT_GET_OPLMN_W_ACT_DONE:
1208                     isRecordLoadResponse = true;
1209                     ar = (AsyncResult) msg.obj;
1210                     data = (byte[]) ar.result;
1211 
1212                     if (ar.exception != null || data == null) {
1213                         loge("Failed getting Operator PLMN with Access Tech Records: "
1214                                 + ar.exception);
1215                         break;
1216                     } else {
1217                         log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
1218                         mOplmnActRecords = PlmnActRecord.getRecords(data);
1219                         if (VDBG) log("OplmnActRecord[]=" + Arrays.toString(mOplmnActRecords));
1220                     }
1221                     break;
1222 
1223                 case EVENT_GET_HPLMN_W_ACT_DONE:
1224                     isRecordLoadResponse = true;
1225                     ar = (AsyncResult) msg.obj;
1226                     data = (byte[]) ar.result;
1227 
1228                     if (ar.exception != null || data == null) {
1229                         loge("Failed getting Home PLMN with Access Tech Records: " + ar.exception);
1230                         break;
1231                     } else {
1232                         log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data));
1233                         mHplmnActRecords = PlmnActRecord.getRecords(data);
1234                         log("HplmnActRecord[]=" + Arrays.toString(mHplmnActRecords));
1235                     }
1236                     break;
1237 
1238                 case EVENT_GET_EHPLMN_DONE:
1239                     isRecordLoadResponse = true;
1240                     ar = (AsyncResult) msg.obj;
1241                     data = (byte[]) ar.result;
1242                     if (ar.exception != null || data == null) {
1243                         loge("Failed getting Equivalent Home PLMNs: " + ar.exception);
1244                         break;
1245                     } else {
1246                         mEhplmns = parseBcdPlmnList(data, "Equivalent Home");
1247                     }
1248                     break;
1249 
1250                 case EVENT_GET_FPLMN_DONE:
1251                     isRecordLoadResponse = true;
1252                     ar = (AsyncResult) msg.obj;
1253                     data = (byte[]) ar.result;
1254                     if (ar.exception != null || data == null) {
1255                         loge("Failed getting Forbidden PLMNs: " + ar.exception);
1256                     } else {
1257                         mFplmns = parseBcdPlmnList(data, "Forbidden");
1258                     }
1259                     if (msg.arg1 == HANDLER_ACTION_SEND_RESPONSE) {
1260                         if (VDBG) logv("getForbiddenPlmns(): send async response");
1261                         isRecordLoadResponse = false;
1262                         int key = msg.arg2;
1263                         Message response = retrievePendingTransaction(key).first;
1264                         if (response != null) {
1265                             if (ar.exception == null && data != null && mFplmns != null) {
1266                                 AsyncResult.forMessage(response, Arrays.copyOf(mFplmns,
1267                                         mFplmns.length), null);
1268                             } else {
1269                                 AsyncResult.forMessage(response, null, ar.exception);
1270                             }
1271                             response.sendToTarget();
1272                         } else {
1273                             loge("Failed to retrieve a response message for FPLMN");
1274                             break;
1275                         }
1276                     }
1277                     break;
1278 
1279                 case EVENT_GET_FPLMN_SIZE_DONE:
1280                     ar = (AsyncResult) msg.obj;
1281                     if (ar.exception != null) {
1282                         Message response = (Message) ar.userObj;
1283                         AsyncResult.forMessage(response).exception = ar.exception;
1284                         response.sendToTarget();
1285                         break;
1286                     }
1287                     int key = msg.arg2;
1288                     Pair<Message, Object> transaction = retrievePendingTransaction(key);
1289                     Message response = transaction.first;
1290                     List<String> fplmns = (List<String>) transaction.second;
1291                     int dataLength = (int) ar.result;
1292                     if (dataLength < 0 || dataLength % FPLMN_BYTE_SIZE != 0) {
1293                         loge("Failed to retrieve a correct fplmn size: " + dataLength);
1294                         AsyncResult.forMessage(response, -1, null);
1295                         response.sendToTarget();
1296                         break;
1297                     }
1298 
1299                     int maxWritebaleFplmns = dataLength / FPLMN_BYTE_SIZE;
1300                     List<String> fplmnsToWrite;
1301                     if (fplmns.size() <= maxWritebaleFplmns) {
1302                         fplmnsToWrite = fplmns;
1303                     } else {
1304                         fplmnsToWrite = fplmns.subList(0, maxWritebaleFplmns);
1305                     }
1306                     key = storePendingTransaction(response, fplmnsToWrite);
1307                     byte[] encodededFplmns = IccUtils.encodeFplmns(fplmns, dataLength);
1308                     mFh.updateEFTransparent(
1309                             EF_FPLMN,
1310                             encodededFplmns,
1311                             obtainMessage(
1312                                     EVENT_SET_FPLMN_DONE,
1313                                     msg.arg1,
1314                                     key));
1315                     break;
1316 
1317                 case EVENT_SET_FPLMN_DONE:
1318                     ar = (AsyncResult) msg.obj;
1319                     if (ar.exception != null) {
1320                         loge("Failed setting Forbidden PLMNs: " + ar.exception);
1321                     } else {
1322                         transaction = retrievePendingTransaction(msg.arg2);
1323                         response = transaction.first;
1324                         mFplmns = ((List<String>) transaction.second).toArray(new String[0]);
1325                         if (msg.arg1 == HANDLER_ACTION_SEND_RESPONSE) {
1326                             AsyncResult.forMessage(response, mFplmns.length, null);
1327                             response.sendToTarget();
1328                         }
1329                         log("Successfully setted fplmns " + ar.result);
1330                     }
1331                     break;
1332 
1333                 case EVENT_GET_PSISMSC_DONE:
1334                     isRecordLoadResponse = true;
1335                     ar = (AsyncResult) msg.obj;
1336                     if (ar.exception != null) {
1337                         loge("Failed to read USIM EF_PSISMSC field error=" + ar.exception);
1338                     } else {
1339                         data = (byte[]) ar.result;
1340                         if (data != null && data.length > 0) {
1341                             mPsiSmsc = parseEfPsiSmsc(data);
1342                             if (VDBG) {
1343                                 log("SIMRecords - EF_PSISMSC value = " + mPsiSmsc);
1344                             }
1345                         }
1346                     }
1347                     break;
1348 
1349                 case EVENT_GET_SMSS_RECORD_DONE:
1350                     isRecordLoadResponse = true;
1351                     ar = (AsyncResult) msg.obj;
1352                     if (ar.exception != null) {
1353                         loge("Failed to read USIM EF_SMSS field error=" + ar.exception);
1354                     } else {
1355                         mSmssValues = (byte[]) ar.result;
1356                         if (VDBG) {
1357                             log("SIMRecords - EF_SMSS TPMR value = " + getSmssTpmrValue());
1358                         }
1359                     }
1360                     break;
1361 
1362                 default:
1363                     super.handleMessage(msg);   // IccRecords handles generic record load responses
1364             }
1365         } catch (RuntimeException exc) {
1366             // I don't want these exceptions to be fatal
1367             logw("Exception parsing SIM record", exc);
1368         } finally {
1369             // Count up record load responses even if they are fails
1370             if (isRecordLoadResponse) {
1371                 onRecordLoaded();
1372             }
1373         }
1374     }
1375 
1376     private class EfPlLoaded implements IccRecordLoaded {
getEfName()1377         public String getEfName() {
1378             return "EF_PL";
1379         }
1380 
onRecordLoaded(AsyncResult ar)1381         public void onRecordLoaded(AsyncResult ar) {
1382             mEfPl = (byte[]) ar.result;
1383             if (DBG) log("EF_PL=" + IccUtils.bytesToHexString(mEfPl));
1384         }
1385     }
1386 
1387     private class EfUsimLiLoaded implements IccRecordLoaded {
getEfName()1388         public String getEfName() {
1389             return "EF_LI";
1390         }
1391 
onRecordLoaded(AsyncResult ar)1392         public void onRecordLoaded(AsyncResult ar) {
1393             mEfLi = (byte[]) ar.result;
1394             if (DBG) log("EF_LI=" + IccUtils.bytesToHexString(mEfLi));
1395         }
1396     }
1397 
1398     @Override
handleFileUpdate(int efid)1399     protected void handleFileUpdate(int efid) {
1400         switch(efid) {
1401             case EF_MBDN:
1402                 mRecordsToLoad++;
1403                 new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
1404                         mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
1405                 break;
1406             case EF_MAILBOX_CPHS:
1407                 mRecordsToLoad++;
1408                 new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS, EF_EXT1,
1409                         1, obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
1410                 break;
1411             case EF_CSP_CPHS:
1412                 mRecordsToLoad++;
1413                 log("[CSP] SIM Refresh for EF_CSP_CPHS");
1414                 mFh.loadEFTransparent(EF_CSP_CPHS,
1415                         obtainMessage(EVENT_GET_CSP_CPHS_DONE));
1416                 break;
1417             case EF_FDN:
1418                 if (DBG) log("SIM Refresh called for EF_FDN");
1419                 mParentApp.queryFdn();
1420                 mAdnCache.reset();
1421                 break;
1422             case EF_MSISDN:
1423                 mRecordsToLoad++;
1424                 log("SIM Refresh called for EF_MSISDN");
1425                 new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,
1426                         obtainMessage(EVENT_GET_MSISDN_DONE));
1427                 break;
1428             case EF_CFIS:
1429             case EF_CFF_CPHS:
1430                 log("SIM Refresh called for EF_CFIS or EF_CFF_CPHS");
1431                 loadCallForwardingRecords();
1432                 break;
1433             default:
1434                 // For now, fetch all records if this is not a
1435                 // voicemail number.
1436                 // TODO: Handle other cases, instead of fetching all.
1437                 mLoaded.set(false);
1438                 mAdnCache.reset();
1439                 fetchSimRecords();
1440                 break;
1441         }
1442     }
1443 
1444     /**
1445      * Dispatch 3GPP format message to registrant ({@code GsmCdmaPhone}) to pass to the 3GPP SMS
1446      * dispatcher for delivery.
1447      */
dispatchGsmMessage(SmsMessage message)1448     private void dispatchGsmMessage(SmsMessage message) {
1449         mNewSmsRegistrants.notifyResult(message);
1450     }
1451 
handleSms(byte[] ba)1452     private void handleSms(byte[] ba) {
1453         if (DBG) log("handleSms status : " + ba[0]);
1454 
1455         // ba[0] is status byte. (see 3GPP TS 51.011 10.5.3)
1456         if ((ba[0] & 0x07) == STATUS_ON_ICC_UNREAD) {
1457             int n = ba.length;
1458 
1459             // Note: Data may include trailing FF's. That's OK; message
1460             // should still parse correctly.
1461             byte[] pdu = new byte[n - 1];
1462             System.arraycopy(ba, 1, pdu, 0, n - 1);
1463             SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
1464 
1465             dispatchGsmMessage(message);
1466         }
1467     }
1468 
handleSmses(ArrayList<byte[]> messages)1469     private void handleSmses(ArrayList<byte[]> messages) {
1470         int count = messages.size();
1471 
1472         for (int i = 0; i < count; i++) {
1473             byte[] ba = messages.get(i);
1474 
1475             if (DBG) log("handleSmses status " + i + ": " + ba[0]);
1476 
1477             // ba[0] is status byte. (see 3GPP TS 51.011 10.5.3)
1478             if ((ba[0] & 0x07) == STATUS_ON_ICC_UNREAD) {
1479                 int n = ba.length;
1480 
1481                 // Note: Data may include trailing FF's. That's OK; message
1482                 // should still parse correctly.
1483                 byte[] pdu = new byte[n - 1];
1484                 System.arraycopy(ba, 1, pdu, 0, n - 1);
1485                 SmsMessage message = SmsMessage.createFromPdu(pdu, SmsConstants.FORMAT_3GPP);
1486 
1487                 dispatchGsmMessage(message);
1488 
1489                 ba[0] = (byte) STATUS_ON_ICC_READ;
1490 
1491                 if (false) { // FIXME: writing seems to crash RdoServD
1492                     mFh.updateEFLinearFixed(EF_SMS,
1493                             i, ba, null, obtainMessage(EVENT_MARK_SMS_READ_DONE, i));
1494                 }
1495             }
1496         }
1497     }
1498 
1499     @Override
onRecordLoaded()1500     protected void onRecordLoaded() {
1501         // One record loaded successfully or failed, In either case
1502         // we need to update the recordsToLoad count
1503         mRecordsToLoad -= 1;
1504         if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested);
1505 
1506         if (getRecordsLoaded()) {
1507             onAllRecordsLoaded();
1508         } else if (getLockedRecordsLoaded() || getNetworkLockedRecordsLoaded()) {
1509             onLockedAllRecordsLoaded();
1510         } else if (mRecordsToLoad < 0) {
1511             loge("recordsToLoad <0, programmer error suspected");
1512             mRecordsToLoad = 0;
1513         }
1514     }
1515 
setVoiceCallForwardingFlagFromSimRecords()1516     private void setVoiceCallForwardingFlagFromSimRecords() {
1517         if (validEfCfis(mEfCfis)) {
1518             // Refer TS 51.011 Section 10.3.46 for the content description
1519             mCallForwardingStatus = (mEfCfis[1] & 0x01);
1520             log("EF_CFIS: callForwardingEnabled=" + mCallForwardingStatus);
1521         } else if (mEfCff != null) {
1522             mCallForwardingStatus =
1523                     ((mEfCff[0] & CFF_LINE1_MASK) == CFF_UNCONDITIONAL_ACTIVE) ?
1524                             CALL_FORWARDING_STATUS_ENABLED : CALL_FORWARDING_STATUS_DISABLED;
1525             log("EF_CFF: callForwardingEnabled=" + mCallForwardingStatus);
1526         } else {
1527             mCallForwardingStatus = CALL_FORWARDING_STATUS_UNKNOWN;
1528             log("EF_CFIS and EF_CFF not valid. callForwardingEnabled=" + mCallForwardingStatus);
1529         }
1530     }
1531 
setSimLanguageFromEF()1532     private void setSimLanguageFromEF() {
1533         Resources resource = Resources.getSystem();
1534         if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) {
1535             setSimLanguage(mEfLi, mEfPl);
1536         } else {
1537             if (DBG) log ("Not using EF LI/EF PL");
1538         }
1539     }
1540 
onLockedAllRecordsLoaded()1541     private void onLockedAllRecordsLoaded() {
1542         setSimLanguageFromEF();
1543         setVoiceCallForwardingFlagFromSimRecords();
1544         if (mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED) {
1545             mLockedRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
1546         } else if (mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED) {
1547             mNetworkLockedRecordsLoadedRegistrants.notifyRegistrants(
1548                     new AsyncResult(null, null, null));
1549         } else {
1550             loge("onLockedAllRecordsLoaded: unexpected mLockedRecordsReqReason "
1551                     + mLockedRecordsReqReason);
1552         }
1553     }
1554 
1555     @Override
onAllRecordsLoaded()1556     protected void onAllRecordsLoaded() {
1557         if (DBG) log("record load complete");
1558 
1559         setSimLanguageFromEF();
1560         setVoiceCallForwardingFlagFromSimRecords();
1561 
1562         // Some fields require more than one SIM record to set
1563 
1564         String operator = getOperatorNumeric();
1565         if (!TextUtils.isEmpty(operator)) {
1566             log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" +
1567                     operator + "'");
1568             mTelephonyManager.setSimOperatorNumericForPhone(
1569                     mParentApp.getPhoneId(), operator);
1570         } else {
1571             log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping");
1572         }
1573 
1574         String imsi = getIMSI();
1575 
1576         if (!TextUtils.isEmpty(imsi) && imsi.length() >= 3) {
1577             log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + imsi) : ""));
1578             mTelephonyManager.setSimCountryIsoForPhone(
1579                     mParentApp.getPhoneId(), MccTable.countryCodeForMcc(imsi.substring(0, 3)));
1580         } else {
1581             log("onAllRecordsLoaded empty imsi skipping setting mcc");
1582         }
1583 
1584         setVoiceMailByCountry(operator);
1585         mLoaded.set(true);
1586         mRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null));
1587     }
1588 
1589     //***** Private methods
1590 
setVoiceMailByCountry(String spn)1591     private void setVoiceMailByCountry (String spn) {
1592         if (mDestroyed.get()) {
1593             return;
1594         }
1595         if (mVmConfig.containsCarrier(spn)) {
1596             mIsVoiceMailFixed = true;
1597             mVoiceMailNum = mVmConfig.getVoiceMailNumber(spn);
1598             mVoiceMailTag = mVmConfig.getVoiceMailTag(spn);
1599         }
1600     }
1601 
1602     /**
1603      * String[] of forbidden PLMNs will be sent to the Message's handler
1604      * in the result field of an AsyncResult in the response.obj.
1605      */
getForbiddenPlmns(Message response)1606     public void getForbiddenPlmns(Message response) {
1607         int key = storePendingTransaction(response);
1608         mFh.loadEFTransparent(EF_FPLMN, obtainMessage(
1609                     EVENT_GET_FPLMN_DONE, HANDLER_ACTION_SEND_RESPONSE, key));
1610     }
1611 
1612     /**
1613      * Set the forbidden PLMNs on the sim
1614      *
1615      * @param response Response to be send back.
1616      * @param fplmns List of fplmns to be written to SIM.
1617      */
setForbiddenPlmns(Message response, List<String> fplmns)1618     public void setForbiddenPlmns(Message response, List<String> fplmns) {
1619         int key = storePendingTransaction(response, fplmns);
1620         mFh.getEFTransparentRecordSize(
1621                 EF_FPLMN,
1622                 obtainMessage(EVENT_GET_FPLMN_SIZE_DONE, HANDLER_ACTION_SEND_RESPONSE, key));
1623     }
1624 
1625 
1626     @Override
onReady()1627     public void onReady() {
1628         fetchSimRecords();
1629     }
1630 
1631     @Override
onLocked()1632     protected void onLocked() {
1633         if (DBG) log("only fetch EF_LI, EF_PL and EF_ICCID in locked state");
1634         super.onLocked();
1635 
1636         loadEfLiAndEfPl();
1637 
1638         mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
1639         mRecordsToLoad++;
1640     }
1641 
loadEfLiAndEfPl()1642     private void loadEfLiAndEfPl() {
1643         if (mParentApp.getType() == AppType.APPTYPE_USIM) {
1644             mFh.loadEFTransparent(EF_LI,
1645                     obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfUsimLiLoaded()));
1646             mRecordsToLoad++;
1647 
1648             mFh.loadEFTransparent(EF_PL,
1649                     obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded()));
1650             mRecordsToLoad++;
1651         }
1652     }
1653 
loadCallForwardingRecords()1654     private void loadCallForwardingRecords() {
1655         mRecordsRequested = true;
1656         mFh.loadEFLinearFixed(EF_CFIS, 1, obtainMessage(EVENT_GET_CFIS_DONE));
1657         mRecordsToLoad++;
1658         mFh.loadEFTransparent(EF_CFF_CPHS, obtainMessage(EVENT_GET_CFF_DONE));
1659         mRecordsToLoad++;
1660     }
1661 
1662     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
fetchSimRecords()1663     protected void fetchSimRecords() {
1664         mRecordsRequested = true;
1665 
1666         if (DBG) log("fetchSimRecords " + mRecordsToLoad);
1667 
1668         mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE));
1669         mRecordsToLoad++;
1670 
1671         mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE));
1672         mRecordsToLoad++;
1673 
1674         // FIXME should examine EF[MSISDN]'s capability configuration
1675         // to determine which is the voice/data/fax line
1676         new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1,
1677                     obtainMessage(EVENT_GET_MSISDN_DONE));
1678         mRecordsToLoad++;
1679 
1680         // Record number is subscriber profile
1681         mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE));
1682         mRecordsToLoad++;
1683 
1684         mFh.loadEFTransparent(EF_AD, obtainMessage(EVENT_GET_AD_DONE));
1685         mRecordsToLoad++;
1686 
1687         // Record number is subscriber profile
1688         mFh.loadEFLinearFixed(EF_MWIS, 1, obtainMessage(EVENT_GET_MWIS_DONE));
1689         mRecordsToLoad++;
1690 
1691 
1692         // Also load CPHS-style voice mail indicator, which stores
1693         // the same info as EF[MWIS]. If both exist, both are updated
1694         // but the EF[MWIS] data is preferred
1695         // Please note this must be loaded after EF[MWIS]
1696         mFh.loadEFTransparent(
1697                 EF_VOICE_MAIL_INDICATOR_CPHS,
1698                 obtainMessage(EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE));
1699         mRecordsToLoad++;
1700 
1701         // Same goes for Call Forward Status indicator: fetch both
1702         // EF[CFIS] and CPHS-EF, with EF[CFIS] preferred.
1703         loadCallForwardingRecords();
1704 
1705         getSpnFsm(true, null);
1706 
1707         mFh.loadEFTransparent(EF_SPDI, obtainMessage(EVENT_GET_SPDI_DONE));
1708         mRecordsToLoad++;
1709 
1710         mFh.loadEFLinearFixedAll(EF_PNN, obtainMessage(EVENT_GET_PNN_DONE));
1711         mRecordsToLoad++;
1712 
1713         mFh.loadEFLinearFixedAll(EF_OPL, obtainMessage(EVENT_GET_OPL_DONE));
1714         mRecordsToLoad++;
1715 
1716         mFh.loadEFTransparent(EF_SST, obtainMessage(EVENT_GET_SST_DONE));
1717         mRecordsToLoad++;
1718 
1719         mFh.loadEFTransparent(EF_INFO_CPHS, obtainMessage(EVENT_GET_INFO_CPHS_DONE));
1720         mRecordsToLoad++;
1721 
1722         mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE));
1723         mRecordsToLoad++;
1724 
1725         mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE));
1726         mRecordsToLoad++;
1727 
1728         mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE));
1729         mRecordsToLoad++;
1730 
1731         mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE));
1732         mRecordsToLoad++;
1733 
1734         mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE));
1735         mRecordsToLoad++;
1736 
1737         mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE));
1738         mRecordsToLoad++;
1739 
1740         mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE));
1741         mRecordsToLoad++;
1742 
1743         mFh.loadEFTransparent(EF_FPLMN, obtainMessage(
1744                     EVENT_GET_FPLMN_DONE, HANDLER_ACTION_NONE, -1));
1745         mRecordsToLoad++;
1746 
1747         loadEfLiAndEfPl();
1748         mFh.getEFLinearRecordSize(EF_SMS, obtainMessage(EVENT_GET_SMS_RECORD_SIZE_DONE));
1749         mRecordsToLoad++;
1750 
1751         mFh.loadEFLinearFixed(EF_PSISMSC, 1, obtainMessage(EVENT_GET_PSISMSC_DONE));
1752         mRecordsToLoad++;
1753 
1754         // XXX should seek instead of examining them all
1755         if (false) { // XXX
1756             mFh.loadEFLinearFixedAll(EF_SMS, obtainMessage(EVENT_GET_ALL_SMS_DONE));
1757             mRecordsToLoad++;
1758         }
1759 
1760         mFh.loadEFTransparent(EF_SMSS, obtainMessage(EVENT_GET_SMSS_RECORD_DONE));
1761         mRecordsToLoad++;
1762 
1763         if (CRASH_RIL) {
1764             String sms = "0107912160130310f20404d0110041007030208054832b0120"
1765                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1766                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1767                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1768                          + "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
1769                          + "ffffffffffffffffffffffffffffff";
1770             byte[] ba = IccUtils.hexStringToBytes(sms);
1771 
1772             mFh.updateEFLinearFixed(EF_SMS, 1, ba, null,
1773                             obtainMessage(EVENT_MARK_SMS_READ_DONE, 1));
1774         }
1775         if (DBG) log("fetchSimRecords " + mRecordsToLoad + " requested: " + mRecordsRequested);
1776     }
1777 
1778     @Override
1779     @CarrierNameDisplayConditionBitmask
getCarrierNameDisplayCondition()1780     public int getCarrierNameDisplayCondition() {
1781         return mCarrierNameDisplayCondition;
1782     }
1783 
1784     /**
1785      * States of Get SPN Finite State Machine which only used by getSpnFsm()
1786      */
1787     @UnsupportedAppUsage(implicitMember =
1788             "values()[Lcom/android/internal/telephony/uicc/SIMRecords$GetSpnFsmState;")
1789     private enum GetSpnFsmState {
1790         IDLE,               // No initialized
1791         @UnsupportedAppUsage
1792         INIT,               // Start FSM
1793         @UnsupportedAppUsage
1794         READ_SPN_3GPP,      // Load EF_SPN firstly
1795         @UnsupportedAppUsage
1796         READ_SPN_CPHS,      // Load EF_SPN_CPHS secondly
1797         @UnsupportedAppUsage
1798         READ_SPN_SHORT_CPHS // Load EF_SPN_SHORT_CPHS last
1799     }
1800 
1801     /**
1802      * Finite State Machine to load Service Provider Name , which can be stored
1803      * in either EF_SPN (3GPP), EF_SPN_CPHS, or EF_SPN_SHORT_CPHS (CPHS4.2)
1804      *
1805      * After starting, FSM will search SPN EFs in order and stop after finding
1806      * the first valid SPN
1807      *
1808      * If the FSM gets restart while waiting for one of
1809      * SPN EFs results (i.e. a SIM refresh occurs after issuing
1810      * read EF_CPHS_SPN), it will re-initialize only after
1811      * receiving and discarding the unfinished SPN EF result.
1812      *
1813      * @param start set true only for initialize loading
1814      * @param ar the AsyncResult from loadEFTransparent
1815      *        ar.exception holds exception in error
1816      *        ar.result is byte[] for data in success
1817      */
1818     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getSpnFsm(boolean start, AsyncResult ar)1819     private void getSpnFsm(boolean start, AsyncResult ar) {
1820         byte[] data;
1821 
1822         if (start) {
1823             // Check previous state to see if there is outstanding
1824             // SPN read
1825             if (mSpnState == GetSpnFsmState.READ_SPN_3GPP
1826                     || mSpnState == GetSpnFsmState.READ_SPN_CPHS
1827                     || mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS
1828                     || mSpnState == GetSpnFsmState.INIT) {
1829                 // Set INIT then return so the INIT code
1830                 // will run when the outstanding read done.
1831                 mSpnState = GetSpnFsmState.INIT;
1832                 return;
1833             } else {
1834                 mSpnState = GetSpnFsmState.INIT;
1835             }
1836         }
1837 
1838         switch(mSpnState){
1839             case INIT:
1840                 setServiceProviderName(null);
1841 
1842                 mFh.loadEFTransparent(EF_SPN,
1843                         obtainMessage(EVENT_GET_SPN_DONE));
1844                 mRecordsToLoad++;
1845 
1846                 mSpnState = GetSpnFsmState.READ_SPN_3GPP;
1847                 break;
1848             case READ_SPN_3GPP:
1849                 if (ar != null && ar.exception == null) {
1850                     data = (byte[]) ar.result;
1851 
1852                     // Reference: 3GPP TS 31.102 section 4.2.12 EF_SPN
1853                     // The first byte is display condition.
1854                     mCarrierNameDisplayCondition =
1855                             convertSpnDisplayConditionToBitmask(data[0] & 0xff);
1856 
1857                     setServiceProviderName(IccUtils.adnStringFieldToString(
1858                                 data, 1, data.length - 1));
1859                     // for card double-check and brand override
1860                     // we have to do this:
1861                     final String spn = getServiceProviderName();
1862 
1863                     if (spn == null || spn.length() == 0) {
1864                         mSpnState = GetSpnFsmState.READ_SPN_CPHS;
1865                     } else {
1866                         if (DBG) log("Load EF_SPN: " + spn
1867                                 + " carrierNameDisplayCondition: " + mCarrierNameDisplayCondition);
1868                         mTelephonyManager.setSimOperatorNameForPhone(
1869                                 mParentApp.getPhoneId(), spn);
1870 
1871                         mSpnState = GetSpnFsmState.IDLE;
1872                     }
1873                 } else {
1874                     mSpnState = GetSpnFsmState.READ_SPN_CPHS;
1875                 }
1876 
1877                 if (mSpnState == GetSpnFsmState.READ_SPN_CPHS) {
1878                     mFh.loadEFTransparent( EF_SPN_CPHS,
1879                             obtainMessage(EVENT_GET_SPN_DONE));
1880                     mRecordsToLoad++;
1881 
1882                     mCarrierNameDisplayCondition = DEFAULT_CARRIER_NAME_DISPLAY_CONDITION;
1883                 }
1884                 break;
1885             case READ_SPN_CPHS:
1886                 if (ar != null && ar.exception == null) {
1887                     data = (byte[]) ar.result;
1888 
1889                     setServiceProviderName(IccUtils.adnStringFieldToString(
1890                                 data, 0, data.length));
1891                     // for card double-check and brand override
1892                     // we have to do this:
1893                     final String spn = getServiceProviderName();
1894 
1895                     if (spn == null || spn.length() == 0) {
1896                         mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
1897                     } else {
1898                         // Display CPHS Operator Name only when not roaming
1899                         mCarrierNameDisplayCondition = 0;
1900 
1901                         if (DBG) log("Load EF_SPN_CPHS: " + spn);
1902                         mTelephonyManager.setSimOperatorNameForPhone(
1903                                 mParentApp.getPhoneId(), spn);
1904 
1905                         mSpnState = GetSpnFsmState.IDLE;
1906                     }
1907                 } else {
1908                     mSpnState = GetSpnFsmState.READ_SPN_SHORT_CPHS;
1909                 }
1910 
1911                 if (mSpnState == GetSpnFsmState.READ_SPN_SHORT_CPHS) {
1912                     mFh.loadEFTransparent(
1913                             EF_SPN_SHORT_CPHS, obtainMessage(EVENT_GET_SPN_DONE));
1914                     mRecordsToLoad++;
1915                 }
1916                 break;
1917             case READ_SPN_SHORT_CPHS:
1918                 if (ar != null && ar.exception == null) {
1919                     data = (byte[]) ar.result;
1920 
1921                     setServiceProviderName(IccUtils.adnStringFieldToString(
1922                                 data, 0, data.length));
1923                     // for card double-check and brand override
1924                     // we have to do this:
1925                     final String spn = getServiceProviderName();
1926 
1927                     if (spn == null || spn.length() == 0) {
1928                         if (DBG) log("No SPN loaded in either CHPS or 3GPP");
1929                     } else {
1930                         // Display CPHS Operator Name only when not roaming
1931                         mCarrierNameDisplayCondition = 0;
1932 
1933                         if (DBG) log("Load EF_SPN_SHORT_CPHS: " + spn);
1934                         mTelephonyManager.setSimOperatorNameForPhone(
1935                                 mParentApp.getPhoneId(), spn);
1936                     }
1937                 } else {
1938                     setServiceProviderName(null);
1939                     if (DBG) log("No SPN loaded in either CHPS or 3GPP");
1940                 }
1941 
1942                 mSpnState = GetSpnFsmState.IDLE;
1943                 break;
1944             default:
1945                 mSpnState = GetSpnFsmState.IDLE;
1946         }
1947     }
1948 
1949     /**
1950      * Parse TS 51.011 EF[SPDI] record
1951      * This record contains the list of numeric network IDs that
1952      * are treated specially when determining SPN display
1953      */
parseEfSpdi(byte[] data)1954     private void parseEfSpdi(byte[] data) {
1955         SimTlv tlv = new SimTlv(data, 0, data.length);
1956 
1957         byte[] plmnEntries = null;
1958 
1959         for ( ; tlv.isValidObject() ; tlv.nextObject()) {
1960             // Skip SPDI tag, if existant
1961             if (tlv.getTag() == TAG_SPDI) {
1962               tlv = new SimTlv(tlv.getData(), 0, tlv.getData().length);
1963             }
1964             // There should only be one TAG_SPDI_PLMN_LIST
1965             if (tlv.getTag() == TAG_SPDI_PLMN_LIST) {
1966                 plmnEntries = tlv.getData();
1967                 break;
1968             }
1969         }
1970 
1971         if (plmnEntries == null) {
1972             return;
1973         }
1974 
1975         List<String> tmpSpdi = new ArrayList<>(plmnEntries.length / 3);
1976         for (int i = 0; i + 2 < plmnEntries.length; i += 3) {
1977             String plmnCode = IccUtils.bcdPlmnToString(plmnEntries, i);
1978             if (!TextUtils.isEmpty(plmnCode)) {
1979                 tmpSpdi.add(plmnCode);
1980             }
1981         }
1982         log("parseEfSpdi: " + tmpSpdi);
1983 
1984         mSpdi = tmpSpdi.toArray(new String[tmpSpdi.size()]);
1985     }
1986 
1987     /**
1988      * Parse EF PLMN Network Name (PNN) record from SIM
1989      * Reference: 3GPP TS 31.102 Section 4.2.58.
1990      */
parseEfPnn(ArrayList<byte[]> dataArray)1991     private void parseEfPnn(ArrayList<byte[]> dataArray) {
1992         if (dataArray == null) return;
1993 
1994         final int count = dataArray.size();
1995         List<PlmnNetworkName> tmpPnns = new ArrayList<>(count);
1996         for (int i = 0; i < count; i++) {
1997             byte[] data = dataArray.get(i);
1998             SimTlv tlv = new SimTlv(data, 0, data.length);
1999 
2000             String longName = null;
2001             String shortName = null;
2002             for (; tlv.isValidObject(); tlv.nextObject()) {
2003                 switch (tlv.getTag()) {
2004                     case TAG_FULL_NETWORK_NAME:
2005                         longName = IccUtils.networkNameToString(tlv.getData(), 0,
2006                                 tlv.getData().length);
2007                         break;
2008 
2009                     case TAG_SHORT_NETWORK_NAME:
2010                         shortName = IccUtils.networkNameToString(tlv.getData(), 0,
2011                                 tlv.getData().length);
2012                         break;
2013 
2014                     case TAG_PLMN_ADDITIONAL_INFORMATION:
2015                         // TODO(b/154300344): read PLMN Additional Information.
2016                         break;
2017                 }
2018             }
2019             // PNNs must maintain their original indices. They will be referred to by index in OPL.
2020             tmpPnns.add(new PlmnNetworkName(longName, shortName));
2021         }
2022         log("parseEfPnn: " + tmpPnns);
2023 
2024         mPnns = tmpPnns.toArray(new PlmnNetworkName[0]);
2025 
2026         // For compatiblility with legacy code.
2027         if (mPnns.length > 0) mPnnHomeName = mPnns[0].getName();
2028     }
2029 
2030     /**
2031      * Parse EF Operator PLMN List (OPL) record from SIM
2032      * Reference: 3GPP TS 31.102 Section 4.2.59.
2033      */
parseEfOpl(ArrayList<byte[]> dataArray)2034     private void parseEfOpl(ArrayList<byte[]> dataArray) {
2035         if (dataArray == null) return;
2036 
2037         final int count = dataArray.size();
2038         List<OperatorPlmnInfo> tmpOpl = new ArrayList<>(count);
2039         for (int i = 0; i < count; i++) {
2040             byte[] data = dataArray.get(i);
2041             // data.length is 8 as defined in 3GPP TS 31.102 Section 4.2.59.
2042             // Byte 0 to 2 are for PLMN.
2043             // Byte 3 and 4 are for lacTacStart.
2044             // Byte 5 and 6 are for lacTacEnd.
2045             // Byte 7 is for PNN Record Identifier.
2046             if (data.length != 8) {
2047                 loge("Invalid length for OPL record " + IccUtils.bytesToHexString(data));
2048                 continue;
2049             }
2050 
2051             // A BCD value of 'D' in any of the MCC and/or MNC digits shall be used to indicate
2052             // a "wild" value for that corresponding MCC/MNC digit.
2053             String plmn = IccUtils.bcdPlmnToString(data, 0);
2054             if (plmn.length() < PLMN_MIN_LENGTH) {
2055                 loge("Invalid length for decoded PLMN " + plmn);
2056                 continue;
2057             }
2058             int lacTacStart = IccUtils.bytesToInt(data, 3, 2);
2059             int lacTacEnd = IccUtils.bytesToInt(data, 5, 2);
2060             int pnnRecordId = IccUtils.bytesToInt(data, 7, 1);
2061 
2062             tmpOpl.add(new OperatorPlmnInfo(plmn, lacTacStart, lacTacEnd, pnnRecordId));
2063         }
2064         log("parseEfOpl: " + tmpOpl);
2065         mOpl = tmpOpl.toArray(new OperatorPlmnInfo[0]);
2066     }
2067 
2068     /**
2069      * convert a byte array of packed plmns to an array of strings
2070      */
parseBcdPlmnList(byte[] data, String description)2071     private String[] parseBcdPlmnList(byte[] data, String description) {
2072         final int packedBcdPlmnLenBytes = 3;
2073         log("Received " + description + " PLMNs, raw=" + IccUtils.bytesToHexString(data));
2074         if (data.length == 0 || (data.length % packedBcdPlmnLenBytes) != 0) {
2075             loge("Received invalid " + description + " PLMN list");
2076             return null;
2077         }
2078         int numPlmns = data.length / packedBcdPlmnLenBytes;
2079         int numValidPlmns = 0;
2080         String[] parsed = new String[numPlmns];
2081         for (int i = 0; i < numPlmns; i++) {
2082             parsed[numValidPlmns] = IccUtils.bcdPlmnToString(data, i * packedBcdPlmnLenBytes);
2083             // we count the valid (non empty) records and only increment if valid
2084             if (!TextUtils.isEmpty(parsed[numValidPlmns])) numValidPlmns++;
2085         }
2086         String[] ret = Arrays.copyOf(parsed, numValidPlmns);
2087         if (VDBG) logv(description + " PLMNs: " + Arrays.toString(ret));
2088         return ret;
2089     }
2090 
2091     /**
2092      * check to see if Mailbox Number is allocated and activated in CPHS SST
2093      */
2094     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
isCphsMailboxEnabled()2095     private boolean isCphsMailboxEnabled() {
2096         if (mCphsInfo == null)  return false;
2097         return ((mCphsInfo[1] & CPHS_SST_MBN_MASK) == CPHS_SST_MBN_ENABLED );
2098     }
2099 
2100     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2101     @Override
log(String s)2102     protected void log(String s) {
2103         if (mParentApp != null) {
2104             Rlog.d(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s);
2105         } else {
2106             Rlog.d(LOG_TAG, "[SIMRecords] " + s);
2107         }
2108     }
2109 
2110     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
2111     @Override
loge(String s)2112     protected void loge(String s) {
2113         if (mParentApp != null) {
2114             Rlog.e(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s);
2115         } else {
2116             Rlog.e(LOG_TAG, "[SIMRecords] " + s);
2117         }
2118     }
2119 
logw(String s, Throwable tr)2120     protected void logw(String s, Throwable tr) {
2121         if (mParentApp != null) {
2122             Rlog.w(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s, tr);
2123         } else {
2124             Rlog.w(LOG_TAG, "[SIMRecords] " + s, tr);
2125         }
2126     }
2127 
2128     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
logv(String s)2129     protected void logv(String s) {
2130         if (mParentApp != null) {
2131             Rlog.v(LOG_TAG, "[SIMRecords-" + mParentApp.getPhoneId() + "] " + s);
2132         } else {
2133             Rlog.v(LOG_TAG, "[SIMRecords] " + s);
2134         }
2135     }
2136 
2137     /**
2138      * Return true if "Restriction of menu options for manual PLMN selection"
2139      * bit is set or EF_CSP data is unavailable, return false otherwise.
2140      */
2141     @Override
isCspPlmnEnabled()2142     public boolean isCspPlmnEnabled() {
2143         return mCspPlmnEnabled;
2144     }
2145 
2146     /**
2147      * Parse EF_CSP data and check if
2148      * "Restriction of menu options for manual PLMN selection" is
2149      * Enabled/Disabled
2150      *
2151      * @param data EF_CSP hex data.
2152      */
handleEfCspData(byte[] data)2153     private void handleEfCspData(byte[] data) {
2154         // As per spec CPHS4_2.WW6, CPHS B.4.7.1, EF_CSP contains CPHS defined
2155         // 18 bytes (i.e 9 service groups info) and additional data specific to
2156         // operator. The valueAddedServicesGroup is not part of standard
2157         // services. This is operator specific and can be programmed any where.
2158         // Normally this is programmed as 10th service after the standard
2159         // services.
2160         int usedCspGroups = data.length / 2;
2161         // This is the "Service Group Number" of "Value Added Services Group".
2162         byte valueAddedServicesGroup = (byte)0xC0;
2163 
2164         mCspPlmnEnabled = true;
2165         for (int i = 0; i < usedCspGroups; i++) {
2166              if (data[2 * i] == valueAddedServicesGroup) {
2167                  log("[CSP] found ValueAddedServicesGroup, value " + data[(2 * i) + 1]);
2168                  if ((data[(2 * i) + 1] & 0x80) == 0x80) {
2169                      // Bit 8 is for
2170                      // "Restriction of menu options for manual PLMN selection".
2171                      // Operator Selection menu should be enabled.
2172                      mCspPlmnEnabled = true;
2173                  } else {
2174                      mCspPlmnEnabled = false;
2175                      // Operator Selection menu should be disabled.
2176                      // Operator Selection Mode should be set to Automatic.
2177                      log("[CSP] Set Automatic Network Selection");
2178                      mNetworkSelectionModeAutomaticRegistrants.notifyRegistrants();
2179                  }
2180                  return;
2181              }
2182         }
2183 
2184         log("[CSP] Value Added Service Group (0xC0), not found!");
2185     }
2186 
2187     @VisibleForTesting
setMailboxIndex(int mailboxIndex)2188     public void setMailboxIndex(int mailboxIndex) {
2189         mMailboxIndex = mailboxIndex;
2190     }
2191 
2192     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)2193     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
2194         pw.println("SIMRecords: " + this);
2195         pw.println(" extends:");
2196         super.dump(fd, pw, args);
2197         pw.println(" mVmConfig=" + mVmConfig);
2198         pw.println(" mCallForwardingStatus=" + mCallForwardingStatus);
2199         pw.println(" mSpnState=" + mSpnState);
2200         pw.println(" mCphsInfo=" + IccUtils.bytesToHexString(mCphsInfo));
2201         pw.println(" mCspPlmnEnabled=" + mCspPlmnEnabled);
2202         pw.println(" mEfMWIS[]=" + Arrays.toString(mEfMWIS));
2203         pw.println(" mEfCPHS_MWI[]=" + Arrays.toString(mEfCPHS_MWI));
2204         pw.println(" mEfCff[]=" + Arrays.toString(mEfCff));
2205         pw.println(" mEfCfis[]=" + Arrays.toString(mEfCfis));
2206         pw.println(" mCarrierNameDisplayCondition=" + mCarrierNameDisplayCondition);
2207         pw.println(" mSpdi[]=" + Arrays.toString(mSpdi));
2208         pw.println(" mUsimServiceTable=" + mUsimServiceTable);
2209         pw.println(" mGid1=" + mGid1);
2210         if (mCarrierTestOverride.isInTestMode()) {
2211             pw.println(" mFakeGid1=" + mCarrierTestOverride.getFakeGid1());
2212         }
2213         pw.println(" mGid2=" + mGid2);
2214         if (mCarrierTestOverride.isInTestMode()) {
2215             pw.println(" mFakeGid2=" + mCarrierTestOverride.getFakeGid2());
2216         }
2217         pw.println(" mPnnHomeName=" + mPnnHomeName);
2218         if (mCarrierTestOverride.isInTestMode()) {
2219             pw.println(" mFakePnnHomeName=" + mCarrierTestOverride.getFakePnnHomeName());
2220         }
2221         pw.println(" mPlmnActRecords[]=" + Arrays.toString(mPlmnActRecords));
2222         pw.println(" mOplmnActRecords[]=" + Arrays.toString(mOplmnActRecords));
2223         pw.println(" mHplmnActRecords[]=" + Arrays.toString(mHplmnActRecords));
2224         pw.println(" mFplmns[]=" + Arrays.toString(mFplmns));
2225         pw.println(" mEhplmns[]=" + Arrays.toString(mEhplmns));
2226         pw.println(" mPsismsc=" + mPsiSmsc);
2227         pw.println(" TPMR=" + getSmssTpmrValue());
2228         pw.flush();
2229     }
2230 }
2231