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