• 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 com.android.internal.telephony.util.TelephonyUtils.FORCE_VERBOSE_STATE_LOGGING;
20 
21 import android.annotation.IntDef;
22 import android.annotation.NonNull;
23 import android.annotation.Nullable;
24 import android.content.Context;
25 import android.os.AsyncResult;
26 import android.os.Handler;
27 import android.os.Message;
28 import android.os.Registrant;
29 import android.os.RegistrantList;
30 import android.os.SystemClock;
31 import android.telephony.CellIdentity;
32 import android.telephony.SubscriptionInfo;
33 import android.telephony.TelephonyManager;
34 import android.text.TextUtils;
35 import android.util.Log;
36 import android.util.Pair;
37 
38 import com.android.internal.annotations.VisibleForTesting;
39 import com.android.internal.telephony.CommandException;
40 import com.android.internal.telephony.CommandsInterface;
41 import com.android.internal.telephony.MccTable;
42 import com.android.internal.telephony.gsm.SimTlv;
43 import com.android.internal.telephony.util.ArrayUtils;
44 import com.android.telephony.Rlog;
45 
46 import java.io.FileDescriptor;
47 import java.io.FileNotFoundException;
48 import java.io.PrintWriter;
49 import java.io.UnsupportedEncodingException;
50 import java.lang.annotation.Retention;
51 import java.lang.annotation.RetentionPolicy;
52 import java.nio.charset.Charset;
53 import java.util.Arrays;
54 import java.util.HashMap;
55 import java.util.Objects;
56 import java.util.concurrent.atomic.AtomicBoolean;
57 import java.util.concurrent.atomic.AtomicInteger;
58 
59 /**
60  * {@hide}
61  */
62 public abstract class IccRecords extends Handler implements IccConstants {
63     private static final String LOG_TAG = "IccRecords";
64     protected static final boolean DBG = true;
65     protected static final boolean VDBG =  FORCE_VERBOSE_STATE_LOGGING ||
66             Rlog.isLoggable(LOG_TAG, Log.VERBOSE);
67 
68     public static final int PLMN_MIN_LENGTH = CellIdentity.MCC_LENGTH
69             + CellIdentity.MNC_MIN_LENGTH;
70     public static final int PLMN_MAX_LENGTH = CellIdentity.MCC_LENGTH
71             + CellIdentity.MNC_MAX_LENGTH;
72 
73     // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
74     private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
75         "302370", "302720", "310260",
76         "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
77         "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
78         "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
79         "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
80         "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
81         "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
82         "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
83         "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
84         "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
85         "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
86         "405849", "405850", "405851", "405852", "405853", "405854", "405855", "405856",
87         "405857", "405858", "405859", "405860", "405861", "405862", "405863", "405864",
88         "405865", "405866", "405867", "405868", "405869", "405870", "405871", "405872",
89         "405873", "405874", "405875", "405876", "405877", "405878", "405879", "405880",
90         "405881", "405882", "405883", "405884", "405885", "405886", "405908", "405909",
91         "405910", "405911", "405912", "405913", "405914", "405915", "405916", "405917",
92         "405918", "405919", "405920", "405921", "405922", "405923", "405924", "405925",
93         "405926", "405927", "405928", "405929", "405930", "405931", "405932", "502142",
94         "502143", "502145", "502146", "502147", "502148"
95     };
96 
97     // ***** Instance Variables
98     protected AtomicBoolean mDestroyed = new AtomicBoolean(false);
99     protected AtomicBoolean mLoaded = new AtomicBoolean(false);
100     protected Context mContext;
101     protected CommandsInterface mCi;
102     protected IccFileHandler mFh;
103     protected UiccCardApplication mParentApp;
104     protected TelephonyManager mTelephonyManager;
105 
106     protected RegistrantList mRecordsLoadedRegistrants = new RegistrantList();
107     protected RegistrantList mLockedRecordsLoadedRegistrants = new RegistrantList();
108     protected RegistrantList mNetworkLockedRecordsLoadedRegistrants = new RegistrantList();
109     protected RegistrantList mImsiReadyRegistrants = new RegistrantList();
110     protected RegistrantList mRecordsEventsRegistrants = new RegistrantList();
111     protected RegistrantList mNewSmsRegistrants = new RegistrantList();
112     protected RegistrantList mNetworkSelectionModeAutomaticRegistrants = new RegistrantList();
113     protected RegistrantList mSpnUpdatedRegistrants = new RegistrantList();
114     protected RegistrantList mRecordsOverrideRegistrants = new RegistrantList();
115 
116     protected int mRecordsToLoad;  // number of pending load requests
117 
118     protected AdnRecordCache mAdnCache;
119 
120     // ***** Cached SIM State; cleared on channel close
121 
122     // SIM is not locked
123     protected static final int LOCKED_RECORDS_REQ_REASON_NONE = 0;
124     // Records requested for PIN or PUK locked SIM
125     protected static final int LOCKED_RECORDS_REQ_REASON_LOCKED = 1;
126     // Records requested for network locked SIM
127     protected static final int LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED = 2;
128 
129     protected boolean mRecordsRequested = false; // true if we've made requests for the sim records
130     protected int mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
131     // EF_SMSS fields tpmr invalid, min and max declarations
132     protected static final int SMSS_INVALID_TPMR = -1;
133     private static final int TPMR_MIN = 0x00;
134     private static final int TPMR_MAX = 0xFF;
135 
136     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
137     public String mIccId;  // Includes only decimals (no hex)
138 
139     protected String mFullIccId;  // Includes hex characters in ICCID
140     protected String mMsisdn = null;  // My mobile number
141     protected String mMsisdnTag = null;
142     protected String mNewMsisdn = null;
143     protected String mNewMsisdnTag = null;
144     protected String mVoiceMailNum = null;
145     protected String mVoiceMailTag = null;
146     protected String mNewVoiceMailNum = null;
147     protected String mNewVoiceMailTag = null;
148     protected boolean mIsVoiceMailFixed = false;
149     protected String mImsi; // IMSI must be only valid numeric characters 0-9 without padding 'f's
150 
151     protected int mMncLength = UNINITIALIZED;
152     protected int mMailboxIndex = 0; // 0 is no mailbox dailing number associated
153 
154     protected int mSmsCountOnIcc = 0;
155 
156     private String mSpn;
157 
158     protected String mGid1;
159     protected String mGid2;
160 
161     protected String mPnnHomeName;
162 
163     protected String mPrefLang;
164 
165     protected PlmnActRecord[] mHplmnActRecords;
166     protected PlmnActRecord[] mOplmnActRecords;
167     protected PlmnActRecord[] mPlmnActRecords;
168 
169     // A list of PLMN in which the SPN shall be displayed.
170     // Reference: 3GPP TS 31.102 Section 4.2.66
171     protected String[] mSpdi;
172 
173     // A list of PLMN Network Name (PNN).
174     // Reference: 3GPP TS 31.102 Section 4.2.58
175     protected PlmnNetworkName[] mPnns;
176 
177     // Operator PLMN List (OPL).
178     // Reference: 3GPP TS 31.102 Section 4.2.59
179     protected OperatorPlmnInfo[] mOpl;
180 
181 
182     // Carrier name display condition bitmask
183     // Reference: 3GPP TS 131.102 section 4.2.12 EF_SPN Display Condition
184     protected int mCarrierNameDisplayCondition;
185 
186     protected String[] mEhplmns;
187     protected String[] mFplmns;
188 
189     // SIP or TEL URI [ Public Service Identity of the SM-SC]
190     // Reference: TS 31.102 section 4.5.9
191     protected String mPsiSmsc;
192 
193     // EF_SMSS value which is combination of TPMR and Memory exceed flag
194     // Reference: TS 31.102 section 4.2.9
195     protected byte[] mSmssValues;
196 
197     CarrierTestOverride mCarrierTestOverride;
198 
199     //Arbitrary offset for the Handler
200     protected static final int HANDLER_ACTION_BASE = 0x12E500;
201     protected static final int HANDLER_ACTION_NONE = HANDLER_ACTION_BASE + 0;
202     protected static final int HANDLER_ACTION_SEND_RESPONSE = HANDLER_ACTION_BASE + 1;
203     protected static AtomicInteger sNextRequestId = new AtomicInteger(1);
204     protected final HashMap<Integer, Pair<Message, Object>> mPendingTransactions = new HashMap<>();
205     // ***** Constants
206 
207     // Markers for mncLength
208     protected static final int UNINITIALIZED = -1;
209     protected static final int UNKNOWN = 0;
210 
211     // Bitmask for carrier name display condition.
212     @Retention(RetentionPolicy.SOURCE)
213     @IntDef(prefix = {"CARRIER_NAME_DISPLAY_CONDITION_BITMASK_"},
214             value = {CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN,
215                     CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN},
216             flag = true)
217     public @interface CarrierNameDisplayConditionBitmask {}
218     public static final int CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN = 1;
219     public static final int CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN = 2;
220 
221 
222     // See {@link CarrierConfigManager#KEY_SPN_DISPLAY_CONDITION_OVERRIDE_INT}.
223     public static final int INVALID_CARRIER_NAME_DISPLAY_CONDITION_BITMASK = -1;
224 
225     // Display SPN only and only if registered to Home PLMNs.
226     // Display PLMN only and only if registered to Non-Home PLMNs.
227     public static final int DEFAULT_CARRIER_NAME_DISPLAY_CONDITION = 0;
228 
229     // ***** Event Constants
230     public static final int EVENT_MWI = 0; // Message Waiting indication
231     public static final int EVENT_CFI = 1; // Call Forwarding indication
232     public static final int EVENT_SPN = 2; // Service Provider Name
233 
234     public static final int EVENT_GET_ICC_RECORD_DONE = 100;
235     public static final int EVENT_REFRESH = 31; // ICC refresh occurred
236     private static final int EVENT_AKA_AUTHENTICATE_DONE = 90;
237     protected static final int EVENT_GET_SMS_RECORD_SIZE_DONE = 28;
238 
239     protected static final int SYSTEM_EVENT_BASE = 0x100;
240     protected static final int EVENT_APP_READY = 1 + SYSTEM_EVENT_BASE;
241     protected static final int EVENT_APP_LOCKED = 2 + SYSTEM_EVENT_BASE;
242     protected static final int EVENT_APP_NETWORK_LOCKED = 3 + SYSTEM_EVENT_BASE;
243     protected static final int EVENT_APP_DETECTED = 4 + SYSTEM_EVENT_BASE;
244 
245     public static final int CALL_FORWARDING_STATUS_DISABLED = 0;
246     public static final int CALL_FORWARDING_STATUS_ENABLED = 1;
247     public static final int CALL_FORWARDING_STATUS_UNKNOWN = -1;
248 
249     public static final int DEFAULT_VOICE_MESSAGE_COUNT = -2;
250     public static final int UNKNOWN_VOICE_MESSAGE_COUNT = -1;
251 
252     // Maximum time in millisecond to wait for a IccSim Challenge before assuming it will not
253     // arrive and returning null to the callers.
254     private static final long ICC_SIM_CHALLENGE_TIMEOUT_MILLIS = 2500;
255 
256     // TAG value to retrieve EF_PSISMSC from parsed SimTlv object
257     private static final int TAG_TLV_USIM_VALUE_80 = 0x80;
258 
259     // call back received on this upon EF_SMSS record update.
260     public static final int EVENT_SET_SMSS_RECORD_DONE = 201;
261 
262     private static final int EVENT_GET_FDN_DONE = 202;
263 
264     /**
265      * There are two purposes for this class. First, each instance of AuthAsyncResponse acts as a
266      * lock to for calling thead to wait in getIccSimChallengeResponse(). Second, pass the IMS
267      * authentication response to the getIccSimChallengeResponse().
268      */
269     private static class AuthAsyncResponse {
270         public IccIoResult authRsp;
271         public Throwable exception;
272     }
273 
274     @Override
toString()275     public String toString() {
276         String iccIdToPrint = SubscriptionInfo.getPrintableId(mFullIccId);
277         return "mDestroyed=" + mDestroyed
278                 + " mContext=" + mContext
279                 + " mCi=" + mCi
280                 + " mFh=" + mFh
281                 + " mParentApp=" + mParentApp
282                 + " recordsToLoad=" + mRecordsToLoad
283                 + " adnCache=" + mAdnCache
284                 + " recordsRequested=" + mRecordsRequested
285                 + " lockedRecordsReqReason=" + mLockedRecordsReqReason
286                 + " iccid=" + iccIdToPrint
287                 + (mCarrierTestOverride.isInTestMode() ? "mFakeIccid="
288                 + mCarrierTestOverride.getFakeIccid() : "")
289                 + " msisdnTag=" + mMsisdnTag
290                 + " voiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum)
291                 + " voiceMailTag=" + mVoiceMailTag
292                 + " voiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum)
293                 + " newVoiceMailTag=" + mNewVoiceMailTag
294                 + " isVoiceMailFixed=" + mIsVoiceMailFixed
295                 + " mImsi=" + ((mImsi != null) ?
296                 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null")
297                 + (mCarrierTestOverride.isInTestMode() ? " mFakeImsi="
298                 + mCarrierTestOverride.getFakeIMSI() : "")
299                 + " mncLength=" + mMncLength
300                 + " mailboxIndex=" + mMailboxIndex
301                 + " spn=" + mSpn
302                 + (mCarrierTestOverride.isInTestMode() ? " mFakeSpn="
303                 + mCarrierTestOverride.getFakeSpn() : "");
304     }
305 
306     /**
307      * Generic ICC record loaded callback. Subclasses can call EF load methods on
308      * {@link IccFileHandler} passing a Message for onLoaded with the what field set to
309      * {@link #EVENT_GET_ICC_RECORD_DONE} and the obj field set to an instance
310      * of this interface. The {@link #handleMessage} method in this class will print a
311      * log message using {@link #getEfName()} and decrement {@link #mRecordsToLoad}.
312      *
313      * If the record load was successful, {@link #onRecordLoaded} will be called with the result.
314      * Otherwise, an error log message will be output by {@link #handleMessage} and
315      * {@link #onRecordLoaded} will not be called.
316      */
317     public interface IccRecordLoaded {
getEfName()318         String getEfName();
onRecordLoaded(AsyncResult ar)319         void onRecordLoaded(AsyncResult ar);
320     }
321 
322     // ***** Constructor
IccRecords(UiccCardApplication app, Context c, CommandsInterface ci)323     public IccRecords(UiccCardApplication app, Context c, CommandsInterface ci) {
324         mContext = c;
325         mCi = ci;
326         mFh = app.getIccFileHandler();
327         mParentApp = app;
328         mTelephonyManager = (TelephonyManager) mContext.getSystemService(
329                 Context.TELEPHONY_SERVICE);
330 
331         mCarrierTestOverride = new CarrierTestOverride(mParentApp.getPhoneId());
332         mCi.registerForIccRefresh(this, EVENT_REFRESH, null);
333 
334         mParentApp.registerForReady(this, EVENT_APP_READY, null);
335         mParentApp.registerForDetected(this, EVENT_APP_DETECTED, null);
336         mParentApp.registerForLocked(this, EVENT_APP_LOCKED, null);
337         mParentApp.registerForNetworkLocked(this, EVENT_APP_NETWORK_LOCKED, null);
338     }
339 
340     // Override IccRecords for testing
setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1, String gid2, String pnn, String spn)341     public void setCarrierTestOverride(String mccmnc, String imsi, String iccid, String gid1,
342             String gid2, String pnn, String spn)  {
343         mCarrierTestOverride.override(mccmnc, imsi, iccid, gid1, gid2, pnn, spn);
344         mTelephonyManager.setSimOperatorNameForPhone(mParentApp.getPhoneId(), spn);
345         mTelephonyManager.setSimOperatorNumericForPhone(mParentApp.getPhoneId(), mccmnc);
346         mRecordsOverrideRegistrants.notifyRegistrants();
347     }
348 
349     /**
350      * Call when the IccRecords object is no longer going to be used.
351      */
dispose()352     public void dispose() {
353         mDestroyed.set(true);
354 
355         mCi.unregisterForIccRefresh(this);
356         mParentApp.unregisterForReady(this);
357         mParentApp.unregisterForDetected(this);
358         mParentApp.unregisterForLocked(this);
359         mParentApp.unregisterForNetworkLocked(this);
360 
361         mParentApp = null;
362         mFh = null;
363         mCi = null;
364         mContext = null;
365         if (mAdnCache != null) {
366             mAdnCache.reset();
367         }
368         mLoaded.set(false);
369     }
370 
onReady()371     protected abstract void onReady();
372 
onDetected()373     protected void onDetected() {
374         mRecordsRequested = false;
375         mLoaded.set(false);
376     }
377 
onLocked()378     protected void onLocked() {
379         // The LOADED state should not be indicated while the lock is effective.
380         mRecordsRequested = false;
381         mLoaded.set(false);
382     }
383 
384     //***** Public Methods
getAdnCache()385     public AdnRecordCache getAdnCache() {
386         return mAdnCache;
387     }
388 
389     /**
390      * Adds a message to the pending requests list by generating a unique (integer)
391      * hash key and returning it. The message should never be null.
392      *
393      * @param msg Message of the transaction to be stored
394      * @return the unique (integer) hash key to retrieve the pending transaction
395      */
storePendingTransaction(Message msg)396     public int storePendingTransaction(Message msg) {
397         return storePendingTransaction(msg, null);
398     }
399 
400     /**
401      * Adds a message and obj pair to the pending requests list by generating a unique (integer)
402      * hash key and returning it. The message should never be null.
403      *
404      * @param msg Message of the transaction to be stored
405      * @param obj Object of the transaction to be stored
406      * @return the unique (integer) hash key to retrieve the pending transaction
407      */
storePendingTransaction(Message msg, Object obj)408     public int storePendingTransaction(Message msg, Object obj) {
409         int key = sNextRequestId.getAndIncrement();
410         Pair<Message, Object> pair = new Pair<Message, Object>(msg, obj);
411         synchronized (mPendingTransactions) {
412             mPendingTransactions.put(key, pair);
413         }
414         return key;
415     }
416 
417     /**
418      * Returns the pending transaction and free it from memory, if any or null
419      *
420      * @param key key of the entry to retrieve
421      * @return The pending transaction.
422      */
retrievePendingTransaction(Integer key)423     public Pair<Message, Object> retrievePendingTransaction(Integer key) {
424         synchronized (mPendingTransactions) {
425             return mPendingTransactions.remove(key);
426         }
427     }
428 
429     /**
430      * Returns the ICC ID stripped at the first hex character. Some SIMs have ICC IDs
431      * containing hex digits; {@link #getFullIccId()} should be used to get the full ID including
432      * hex digits.
433      * @return ICC ID without hex digits
434      */
getIccId()435     public String getIccId() {
436         if (mCarrierTestOverride.isInTestMode()) {
437             String fakeIccId = mCarrierTestOverride.getFakeIccid();
438             if (fakeIccId != null) {
439                 return fakeIccId;
440             }
441         }
442         return mIccId;
443     }
444 
445     /**
446      * Returns the full ICC ID including hex digits.
447      * @return full ICC ID including hex digits
448      */
getFullIccId()449     public String getFullIccId() {
450         return mFullIccId;
451     }
452 
registerForRecordsLoaded(Handler h, int what, Object obj)453     public void registerForRecordsLoaded(Handler h, int what, Object obj) {
454         if (mDestroyed.get()) {
455             return;
456         }
457 
458         Registrant r = new Registrant(h, what, obj);
459         mRecordsLoadedRegistrants.add(r);
460 
461         if (getRecordsLoaded()) {
462             r.notifyRegistrant(new AsyncResult(null, null, null));
463         }
464     }
465 
unregisterForRecordsLoaded(Handler h)466     public void unregisterForRecordsLoaded(Handler h) {
467         mRecordsLoadedRegistrants.remove(h);
468     }
469 
unregisterForRecordsOverride(Handler h)470     public void unregisterForRecordsOverride(Handler h) {
471         mRecordsOverrideRegistrants.remove(h);
472     }
473 
registerForRecordsOverride(Handler h, int what, Object obj)474     public void registerForRecordsOverride(Handler h, int what, Object obj) {
475         if (mDestroyed.get()) {
476             return;
477         }
478 
479         Registrant r = new Registrant(h, what, obj);
480         mRecordsOverrideRegistrants.add(r);
481 
482         if (getRecordsLoaded()) {
483             r.notifyRegistrant(new AsyncResult(null, null, null));
484         }
485     }
486 
487     /**
488      * Register to be notified when records are loaded for a PIN or PUK locked SIM
489      */
registerForLockedRecordsLoaded(Handler h, int what, Object obj)490     public void registerForLockedRecordsLoaded(Handler h, int what, Object obj) {
491         if (mDestroyed.get()) {
492             return;
493         }
494 
495         Registrant r = new Registrant(h, what, obj);
496         mLockedRecordsLoadedRegistrants.add(r);
497 
498         if (getLockedRecordsLoaded()) {
499             r.notifyRegistrant(new AsyncResult(null, null, null));
500         }
501     }
502 
503     /**
504      * Unregister corresponding to registerForLockedRecordsLoaded()
505      */
unregisterForLockedRecordsLoaded(Handler h)506     public void unregisterForLockedRecordsLoaded(Handler h) {
507         mLockedRecordsLoadedRegistrants.remove(h);
508     }
509 
510     /**
511      * Register to be notified when records are loaded for a network locked SIM
512      */
registerForNetworkLockedRecordsLoaded(Handler h, int what, Object obj)513     public void registerForNetworkLockedRecordsLoaded(Handler h, int what, Object obj) {
514         if (mDestroyed.get()) {
515             return;
516         }
517 
518         Registrant r = new Registrant(h, what, obj);
519         mNetworkLockedRecordsLoadedRegistrants.add(r);
520 
521         if (getNetworkLockedRecordsLoaded()) {
522             r.notifyRegistrant(new AsyncResult(null, null, null));
523         }
524     }
525 
526     /**
527      * Unregister corresponding to registerForLockedRecordsLoaded()
528      */
unregisterForNetworkLockedRecordsLoaded(Handler h)529     public void unregisterForNetworkLockedRecordsLoaded(Handler h) {
530         mNetworkLockedRecordsLoadedRegistrants.remove(h);
531     }
532 
registerForImsiReady(Handler h, int what, Object obj)533     public void registerForImsiReady(Handler h, int what, Object obj) {
534         if (mDestroyed.get()) {
535             return;
536         }
537 
538         Registrant r = new Registrant(h, what, obj);
539         mImsiReadyRegistrants.add(r);
540 
541         if (getIMSI() != null) {
542             r.notifyRegistrant(new AsyncResult(null, null, null));
543         }
544     }
unregisterForImsiReady(Handler h)545     public void unregisterForImsiReady(Handler h) {
546         mImsiReadyRegistrants.remove(h);
547     }
548 
registerForSpnUpdate(Handler h, int what, Object obj)549     public void registerForSpnUpdate(Handler h, int what, Object obj) {
550         if (mDestroyed.get()) {
551             return;
552         }
553 
554         Registrant r = new Registrant(h, what, obj);
555         mSpnUpdatedRegistrants.add(r);
556 
557         if (!TextUtils.isEmpty(mSpn)) {
558             r.notifyRegistrant(new AsyncResult(null, null, null));
559         }
560     }
unregisterForSpnUpdate(Handler h)561     public void unregisterForSpnUpdate(Handler h) {
562         mSpnUpdatedRegistrants.remove(h);
563     }
564 
registerForRecordsEvents(Handler h, int what, Object obj)565     public void registerForRecordsEvents(Handler h, int what, Object obj) {
566         Registrant r = new Registrant (h, what, obj);
567         mRecordsEventsRegistrants.add(r);
568 
569         /* Notify registrant of all the possible events. This is to make sure registrant is
570         notified even if event occurred in the past. */
571         r.notifyResult(EVENT_MWI);
572         r.notifyResult(EVENT_CFI);
573     }
574 
unregisterForRecordsEvents(Handler h)575     public void unregisterForRecordsEvents(Handler h) {
576         mRecordsEventsRegistrants.remove(h);
577     }
578 
registerForNewSms(Handler h, int what, Object obj)579     public void registerForNewSms(Handler h, int what, Object obj) {
580         Registrant r = new Registrant (h, what, obj);
581         mNewSmsRegistrants.add(r);
582     }
583 
unregisterForNewSms(Handler h)584     public void unregisterForNewSms(Handler h) {
585         mNewSmsRegistrants.remove(h);
586     }
587 
registerForNetworkSelectionModeAutomatic( Handler h, int what, Object obj)588     public void registerForNetworkSelectionModeAutomatic(
589             Handler h, int what, Object obj) {
590         Registrant r = new Registrant (h, what, obj);
591         mNetworkSelectionModeAutomaticRegistrants.add(r);
592     }
unregisterForNetworkSelectionModeAutomatic(Handler h)593     public void unregisterForNetworkSelectionModeAutomatic(Handler h) {
594         mNetworkSelectionModeAutomaticRegistrants.remove(h);
595     }
596 
597     /**
598      * Get the International Mobile Subscriber ID (IMSI) on a SIM
599      * for GSM, UMTS and like networks. Default is null if IMSI is
600      * not supported or unavailable.
601      *
602      * @return null if SIM is not yet ready or unavailable
603      */
getIMSI()604     public String getIMSI() {
605         if (mCarrierTestOverride.isInTestMode()) {
606             String fakeImsi = mCarrierTestOverride.getFakeIMSI();
607             if (fakeImsi != null) {
608                 return fakeImsi;
609             }
610         }
611         return mImsi;
612     }
613 
614     /**
615      * Update IMSI record and try to extract the PLMN information and notify registrants.
616      * @param inImsi the IMSI value
617      */
setImsi(String inImsi)618     public void setImsi(String inImsi) {
619         // Remove trailing F's if present in IMSI.
620         mImsi = IccUtils.stripTrailingFs(inImsi);
621         if (!Objects.equals(mImsi, inImsi)) {
622             loge("Invalid IMSI padding digits received.");
623         }
624 
625         if (TextUtils.isEmpty(mImsi)) mImsi = null;
626 
627         if (mImsi != null && !mImsi.matches("[0-9]+")) {
628             loge("Invalid non-numeric IMSI digits received.");
629             mImsi = null;
630         }
631 
632         // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
633         // than 15 (and usually 15).
634         // This will also handle un-set IMSI records (all Fs)
635         if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
636             loge("invalid IMSI " + mImsi);
637             mImsi = null;
638         }
639 
640         log("IMSI: mMncLength=" + mMncLength);
641 
642         if (mImsi != null && mImsi.length() >= 6) {
643             log("IMSI: " + mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)));
644         }
645 
646         // IMSI has changed so the PLMN might have changed as well
647         updateOperatorPlmn();
648 
649         mImsiReadyRegistrants.notifyRegistrants();
650     }
651 
updateOperatorPlmn()652     protected void updateOperatorPlmn() {
653         // In case of a test override, use the test IMSI
654         String imsi = getIMSI();
655 
656         if (imsi != null) {
657             // First try to guess the length based on a table of known 3-digit MNCs.
658             if (((mMncLength == UNKNOWN) || (mMncLength == 2)) && imsi.length() >= 6) {
659                 String mccmncCode = imsi.substring(0, 6);
660                 for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
661                     if (mccmnc.equals(mccmncCode)) {
662                         mMncLength = 3;
663                         log("IMSI: setting1 mMncLength=" + mMncLength);
664                         break;
665                     }
666                 }
667             }
668 
669             // If still unknown, guess using the MCC.
670             if (mMncLength == UNKNOWN) {
671                 try {
672                     int mcc = Integer.parseInt(imsi.substring(0, 3));
673                     mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
674                     log("setting2 mMncLength=" + mMncLength);
675                 } catch (NumberFormatException e) {
676                     loge("Corrupt IMSI! setting3 mMncLength=" + mMncLength);
677                 }
678             }
679 
680             if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED
681                     && imsi.length() >= 3 + mMncLength) {
682                 log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
683                 // finally have both the imsi and the mncLength and
684                 // can parse the imsi properly
685                 MccTable.updateMccMncConfiguration(mContext, imsi.substring(0, 3 + mMncLength));
686             }
687         }
688     }
689 
690     /**
691      * Get the Network Access ID (NAI) on a CSIM for CDMA like networks. Default is null if IMSI is
692      * not supported or unavailable.
693      *
694      * @return null if NAI is not yet ready or unavailable
695      */
getNAI()696     public String getNAI() {
697         return null;
698     }
699 
getMsisdnNumber()700     public String getMsisdnNumber() {
701         return mMsisdn;
702     }
703 
704     /**
705      * Get the Group Identifier Level 1 (GID1) on a SIM for GSM.
706      * @return null if SIM is not yet ready
707      */
getGid1()708     public String getGid1() {
709         if (mCarrierTestOverride.isInTestMode()) {
710             String fakeGid1 = mCarrierTestOverride.getFakeGid1();
711             if (fakeGid1 != null) {
712                 return fakeGid1;
713             }
714         }
715         return mGid1;
716     }
717 
718     /**
719      * Get the Group Identifier Level 2 (GID2) on a SIM.
720      * @return null if SIM is not yet ready
721      */
getGid2()722     public String getGid2() {
723         if (mCarrierTestOverride.isInTestMode()) {
724             String fakeGid2 = mCarrierTestOverride.getFakeGid2();
725             if (fakeGid2 != null) {
726                 return fakeGid2;
727             }
728         }
729         return mGid2;
730     }
731 
732     /**
733      * Get the PLMN network name on a SIM.
734      * @return null if SIM is not yet ready
735      */
getPnnHomeName()736     public String getPnnHomeName() {
737         if (mCarrierTestOverride.isInTestMode()) {
738             String fakePnnHomeName = mCarrierTestOverride.getFakePnnHomeName();
739             if (fakePnnHomeName != null) {
740                 return fakePnnHomeName;
741             }
742         }
743         return mPnnHomeName;
744     }
745 
getPnns()746     public PlmnNetworkName[] getPnns() {
747         return mPnns;
748     }
749 
getOpl()750     public OperatorPlmnInfo[] getOpl() {
751         return mOpl;
752     }
753 
setMsisdnNumber(String alphaTag, String number, Message onComplete)754     public void setMsisdnNumber(String alphaTag, String number,
755             Message onComplete) {
756         loge("setMsisdn() should not be invoked on base IccRecords");
757         // synthesize a "File Not Found" exception and return it
758         AsyncResult.forMessage(onComplete).exception =
759             (new IccIoResult(0x6A, 0x82, (byte[]) null)).getException();
760         onComplete.sendToTarget();
761     }
762 
getMsisdnAlphaTag()763     public String getMsisdnAlphaTag() {
764         return mMsisdnTag;
765     }
766 
getVoiceMailNumber()767     public String getVoiceMailNumber() {
768         return mVoiceMailNum;
769     }
770 
771     /**
772      * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41).
773      *
774      * @return null if SIM is not yet ready or no RUIM entry
775      */
getServiceProviderName()776     public String getServiceProviderName() {
777         if (mCarrierTestOverride.isInTestMode()) {
778             String fakeSpn = mCarrierTestOverride.getFakeSpn();
779             if (fakeSpn != null) {
780                 return fakeSpn;
781             }
782         }
783         return mSpn;
784     }
785 
786     /**
787      * Return Service Provider Name stored in SIM (EF_SPN=0x6F46) or in RUIM (EF_RUIM_SPN=0x6F41) or
788      * the brand override. The brand override has higher priority than the SPN from SIM.
789      *
790      * @return service provider name.
791      */
792     @Nullable
getServiceProviderNameWithBrandOverride()793     public String getServiceProviderNameWithBrandOverride() {
794         if (mParentApp != null && mParentApp.getUiccProfile() != null) {
795             String brandOverride = mParentApp.getUiccProfile().getOperatorBrandOverride();
796             if (!TextUtils.isEmpty(brandOverride)) {
797                 return brandOverride;
798             }
799         }
800         return mSpn;
801     }
802 
setServiceProviderName(String spn)803     protected void setServiceProviderName(String spn) {
804         if (!TextUtils.equals(mSpn, spn)) {
805             mSpn = spn != null ? spn.trim() : null;
806             mSpnUpdatedRegistrants.notifyRegistrants();
807         }
808     }
809 
810     /**
811      * Set voice mail number to SIM record
812      *
813      * The voice mail number can be stored either in EF_MBDN (TS 51.011) or
814      * EF_MAILBOX_CPHS (CPHS 4.2)
815      *
816      * If EF_MBDN is available, store the voice mail number to EF_MBDN
817      *
818      * If EF_MAILBOX_CPHS is enabled, store the voice mail number to EF_CHPS
819      *
820      * So the voice mail number will be stored in both EFs if both are available
821      *
822      * Return error only if both EF_MBDN and EF_MAILBOX_CPHS fail.
823      *
824      * When the operation is complete, onComplete will be sent to its handler
825      *
826      * @param alphaTag alpha-tagging of the dailing nubmer (upto 10 characters)
827      * @param voiceNumber dailing nubmer (upto 20 digits)
828      *        if the number is start with '+', then set to international TOA
829      * @param onComplete
830      *        onComplete.obj will be an AsyncResult
831      *        ((AsyncResult)onComplete.obj).exception == null on success
832      *        ((AsyncResult)onComplete.obj).exception != null on fail
833      */
setVoiceMailNumber(String alphaTag, String voiceNumber, Message onComplete)834     public abstract void setVoiceMailNumber(String alphaTag, String voiceNumber,
835             Message onComplete);
836 
getVoiceMailAlphaTag()837     public String getVoiceMailAlphaTag() {
838         return mVoiceMailTag;
839     }
840 
841     /**
842      * Sets the SIM voice message waiting indicator records
843      * @param line GSM Subscriber Profile Number, one-based. Only '1' is supported
844      * @param countWaiting The number of messages waiting, if known. Use
845      *                     -1 to indicate that an unknown number of
846      *                      messages are waiting
847      */
setVoiceMessageWaiting(int line, int countWaiting)848     public abstract void setVoiceMessageWaiting(int line, int countWaiting);
849 
850     /**
851      * Called by GsmCdmaPhone to update VoiceMail count
852      */
getVoiceMessageCount()853     public abstract int getVoiceMessageCount();
854 
855     /**
856      * Called by STK Service when REFRESH is received.
857      * @param fileChanged indicates whether any files changed
858      * @param fileList if non-null, a list of EF files that changed
859      */
onRefresh(boolean fileChanged, int[] fileList)860     public abstract void onRefresh(boolean fileChanged, int[] fileList);
861 
getRecordsLoaded()862     public boolean getRecordsLoaded() {
863         return mRecordsToLoad == 0 && mRecordsRequested;
864     }
865 
getLockedRecordsLoaded()866     protected boolean getLockedRecordsLoaded() {
867         return mRecordsToLoad == 0
868                 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_LOCKED;
869     }
870 
getNetworkLockedRecordsLoaded()871     protected boolean getNetworkLockedRecordsLoaded() {
872         return mRecordsToLoad == 0
873                 && mLockedRecordsReqReason == LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED;
874     }
875 
876     //***** Overridden from Handler
877     @Override
handleMessage(Message msg)878     public void handleMessage(Message msg) {
879         AsyncResult ar;
880 
881         switch (msg.what) {
882             case EVENT_APP_READY:
883                 mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
884                 onReady();
885                 break;
886 
887             case EVENT_APP_DETECTED:
888                 mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NONE;
889                 onDetected();
890                 break;
891 
892             case EVENT_APP_LOCKED:
893                 mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_LOCKED;
894                 onLocked();
895                 break;
896 
897             case EVENT_APP_NETWORK_LOCKED:
898                 mLockedRecordsReqReason = LOCKED_RECORDS_REQ_REASON_NETWORK_LOCKED;
899                 onLocked();
900                 break;
901 
902             case EVENT_GET_ICC_RECORD_DONE:
903                 try {
904                     ar = (AsyncResult) msg.obj;
905                     IccRecordLoaded recordLoaded = (IccRecordLoaded) ar.userObj;
906                     if (DBG) log(recordLoaded.getEfName() + " LOADED");
907 
908                     if (ar.exception != null) {
909                         loge("Record Load Exception: " + ar.exception);
910                     } else {
911                         recordLoaded.onRecordLoaded(ar);
912                     }
913                 }catch (RuntimeException exc) {
914                     // I don't want these exceptions to be fatal
915                     loge("Exception parsing SIM record: " + exc);
916                 } finally {
917                     // Count up record load responses even if they are fails
918                     onRecordLoaded();
919                 }
920                 break;
921 
922             case EVENT_REFRESH:
923                 ar = (AsyncResult)msg.obj;
924                 if (DBG) log("Card REFRESH occurred: ");
925                 if (ar.exception == null) {
926                     handleRefresh((IccRefreshResponse)ar.result);
927                 } else {
928                     loge("Icc refresh Exception: " + ar.exception);
929                 }
930                 break;
931 
932             case EVENT_AKA_AUTHENTICATE_DONE:
933                 ar = (AsyncResult) msg.obj;
934                 AuthAsyncResponse rsp = (AuthAsyncResponse) ar.userObj;
935                 if (DBG) log("EVENT_AKA_AUTHENTICATE_DONE");
936 
937                 synchronized (rsp) {
938                     if (ar.exception != null) {
939                         rsp.exception = ar.exception;
940                         loge("Exception ICC SIM AKA: " + ar.exception);
941                     } else if (ar.result == null) {
942                         rsp.exception = new NullPointerException(
943                                 "Null SIM authentication response");
944                         loge("EVENT_AKA_AUTHENTICATE_DONE: null response");
945                     } else {
946                         try {
947                             rsp.authRsp = (IccIoResult) ar.result;
948                             if (VDBG) log("ICC SIM AKA: authRsp = " + rsp.authRsp);
949                         } catch (ClassCastException e) {
950                             rsp.exception = e;
951                             loge("Failed to parse ICC SIM AKA contents: " + e);
952                         }
953                     }
954                     rsp.notifyAll();
955                 }
956 
957                 break;
958 
959             case EVENT_GET_SMS_RECORD_SIZE_DONE:
960                 ar = (AsyncResult) msg.obj;
961 
962                 if (ar.exception != null) {
963                     onRecordLoaded();
964                     loge("Exception in EVENT_GET_SMS_RECORD_SIZE_DONE " + ar.exception);
965                     break;
966                 }
967 
968                 int[] recordSize = (int[])ar.result;
969                 try {
970                     // recordSize[0]  is the record length
971                     // recordSize[1]  is the total length of the EF file
972                     // recordSize[2]  is the number of records in the EF file
973                     mSmsCountOnIcc = recordSize[2];
974                     log("EVENT_GET_SMS_RECORD_SIZE_DONE Size " + recordSize[0]
975                             + " total " + recordSize[1]
976                                     + " record " + recordSize[2]);
977                 } catch (ArrayIndexOutOfBoundsException exc) {
978                     mSmsCountOnIcc = -1;
979                     loge("ArrayIndexOutOfBoundsException in EVENT_GET_SMS_RECORD_SIZE_DONE: "
980                             + exc.toString());
981                 } finally {
982                     onRecordLoaded();
983                 }
984                 break;
985 
986             case EVENT_SET_SMSS_RECORD_DONE:
987                 ar = (AsyncResult) msg.obj;
988                 SmssRecord smssRecord = null;
989                 if (ar.userObj != null) {
990                     smssRecord = (SmssRecord) ar.userObj;
991                 }
992                 if (ar.exception == null && smssRecord.getSmssValue() != null) {
993                     mSmssValues = smssRecord.getSmssValue().clone();
994                 } else {
995                     loge("SIM EF_SMSS field updating error=" + ar.exception);
996                 }
997                 if (smssRecord != null && smssRecord.getMessage() != null) {
998                     Message message = smssRecord.getMessage();
999                     AsyncResult.forMessage(message, ar.result, ar.exception);
1000                     message.sendToTarget();
1001                 } else {
1002                     loge("smssRecord or smssRecord.getMessage() object is null");
1003                 }
1004                 break;
1005 
1006             case EVENT_GET_FDN_DONE:
1007                 ar = (AsyncResult) msg.obj;
1008                 if (ar.exception != null) {
1009                     loge("Failed to read USIM EF_FDN field error=" + ar.exception);
1010                 } else {
1011                     log("EF_FDN read successfully");
1012                 }
1013                 break;
1014 
1015             default:
1016                 super.handleMessage(msg);
1017         }
1018     }
1019 
1020     /**
1021      * Returns the SIM language derived from the EF-LI and EF-PL sim records.
1022      */
getSimLanguage()1023     public String getSimLanguage() {
1024         return mPrefLang;
1025     }
1026 
setSimLanguage(byte[] efLi, byte[] efPl)1027     protected void setSimLanguage(byte[] efLi, byte[] efPl) {
1028         String[] locales = mContext.getAssets().getLocales();
1029         try {
1030             mPrefLang = findBestLanguage(efLi, locales);
1031         } catch (UnsupportedEncodingException uee) {
1032             log("Unable to parse EF-LI: " + Arrays.toString(efLi));
1033         }
1034 
1035         if (mPrefLang == null) {
1036             try {
1037                 mPrefLang = findBestLanguage(efPl, locales);
1038             } catch (UnsupportedEncodingException uee) {
1039                 log("Unable to parse EF-PL: " + Arrays.toString(efLi));
1040             }
1041         }
1042     }
1043 
findBestLanguage(byte[] languages, String[] locales)1044     protected static String findBestLanguage(byte[] languages, String[] locales)
1045             throws UnsupportedEncodingException {
1046         if ((languages == null) || (locales == null)) return null;
1047 
1048         // Each 2-bytes consists of one language
1049         for (int i = 0; (i + 1) < languages.length; i += 2) {
1050             String lang = new String(languages, i, 2, "ISO-8859-1");
1051             for (int j = 0; j < locales.length; j++) {
1052                 if (locales[j] != null && locales[j].length() >= 2 &&
1053                         locales[j].substring(0, 2).equalsIgnoreCase(lang)) {
1054                     return lang;
1055                 }
1056             }
1057         }
1058 
1059         // no match found. return null
1060         return null;
1061     }
1062 
handleFileUpdate(int efid)1063     protected abstract void handleFileUpdate(int efid);
1064 
handleRefresh(IccRefreshResponse refreshResponse)1065     protected void handleRefresh(IccRefreshResponse refreshResponse){
1066         if (refreshResponse == null) {
1067             if (DBG) log("handleRefresh received without input");
1068             return;
1069         }
1070 
1071         if (!TextUtils.isEmpty(refreshResponse.aid) &&
1072                 !refreshResponse.aid.equals(mParentApp.getAid())) {
1073             // This is for different app. Ignore.
1074             return;
1075         }
1076 
1077         switch (refreshResponse.refreshResult) {
1078             case IccRefreshResponse.REFRESH_RESULT_FILE_UPDATE:
1079                 if (DBG) log("handleRefresh with SIM_FILE_UPDATED");
1080                 handleFileUpdate(refreshResponse.efId);
1081                 break;
1082             default:
1083                 // unknown refresh operation
1084                 if (DBG) log("handleRefresh with unknown operation");
1085                 break;
1086         }
1087     }
1088 
onRecordLoaded()1089     protected abstract void onRecordLoaded();
1090 
onAllRecordsLoaded()1091     protected abstract void onAllRecordsLoaded();
1092 
1093     /**
1094      * Retrieves the SPN/PLMN display condition from UICC.
1095      *
1096      * Display of service provider name is required when registered PLMN is neither HPLMN nor a PLMN
1097      * in the service provider PLMN list(EF_SPDI).
1098      *
1099      * Display of PLMN network name is required when registered PLMN is either HPLMN or a PLMN in
1100      * the service provider PLMN list(EF_SPDI).
1101      *
1102      * Reference: 3GPP TS 131.102 section 4.2.12 EF_SPN Display Condition
1103      *
1104      * @return a bitmask represent the carrier name display condition.
1105      */
1106     @CarrierNameDisplayConditionBitmask
getCarrierNameDisplayCondition()1107     public int getCarrierNameDisplayCondition() {
1108         return mCarrierNameDisplayCondition;
1109     }
1110 
1111     /**
1112      * Retrieves the service provider display information. This is a list of PLMNs in which the
1113      * service provider name shall be displayed.
1114      *
1115      * Reference: 3GPP TS 131.102 section 4.2.66 EF_SPDI
1116      *
1117      * @return a list of PLMN(mcc+mnc) if EF_SPDI is existed, otherwise return null.
1118      */
getServiceProviderDisplayInformation()1119     public String[] getServiceProviderDisplayInformation() {
1120         return mSpdi;
1121     }
1122 
1123     /**
1124      * Get home PLMN list.
1125      *
1126      * @see #getEhplmns()
1127      * @see #getServiceProviderDisplayInformation()
1128      *
1129      * @return a list of HPLMN if existed, otherwise return null.
1130      */
getHomePlmns()1131     public String[] getHomePlmns() {
1132         // hplmn from imsi.
1133         String hplmn = getOperatorNumeric();
1134 
1135         // hplmn from ehplmn list.
1136         String[] hplmns = getEhplmns();
1137 
1138         // plmn from ef_spdi.
1139         String[] spdi = getServiceProviderDisplayInformation();
1140 
1141         // Use the plmn from imsi as the hplmn if Ehplmn not present.
1142         if (ArrayUtils.isEmpty(hplmns)) {
1143             hplmns = new String[] {hplmn};
1144         }
1145 
1146         if (!ArrayUtils.isEmpty(spdi)) {
1147             hplmns = ArrayUtils.concatElements(String.class, hplmns, spdi);
1148         }
1149         // If hplmns don't contain hplmn, we need to add hplmn to hplmns
1150         hplmns = ArrayUtils.appendElement(String.class, hplmns, hplmn);
1151         return hplmns;
1152     }
1153 
1154     /**
1155      * Return true if "Restriction of menu options for manual PLMN selection"
1156      * bit is set or EF_CSP data is unavailable, return false otherwise.
1157      * Generally used for GSM/UMTS and the like SIMs.
1158      */
isCspPlmnEnabled()1159     public boolean isCspPlmnEnabled() {
1160         return false;
1161     }
1162 
1163     /**
1164      * Returns the 5 or 6 digit MCC/MNC of the operator that
1165      * provided the SIM card. Returns null of SIM is not yet ready
1166      * or is not valid for the type of IccCard. Generally used for
1167      * GSM/UMTS and the like SIMS
1168      */
getOperatorNumeric()1169     public String getOperatorNumeric() {
1170         return null;
1171     }
1172 
1173     /**
1174      * Get the current Voice call forwarding flag for GSM/UMTS and the like SIMs
1175      *
1176      * @return CALL_FORWARDING_STATUS_XXX (DISABLED/ENABLED/UNKNOWN)
1177      */
getVoiceCallForwardingFlag()1178     public int getVoiceCallForwardingFlag() {
1179         return CALL_FORWARDING_STATUS_UNKNOWN;
1180     }
1181 
1182     /**
1183      * Set the voice call forwarding flag for GSM/UMTS and the like SIMs
1184      *
1185      * @param line to enable/disable
1186      * @param enable
1187      * @param number to which CFU is enabled
1188      */
setVoiceCallForwardingFlag(int line, boolean enable, String number)1189     public void setVoiceCallForwardingFlag(int line, boolean enable, String number) {
1190     }
1191 
1192     /**
1193      * Indicates wether the ICC records have been loaded or not
1194      *
1195      * @return true if the records have been loaded, false otherwise.
1196      */
isLoaded()1197     public boolean isLoaded() {
1198         return mLoaded.get();
1199     }
1200 
1201     /**
1202      * Indicates wether SIM is in provisioned state or not.
1203      * Overridden only if SIM can be dynamically provisioned via OTA.
1204      *
1205      * @return true if provisioned
1206      */
isProvisioned()1207     public boolean isProvisioned () {
1208         return true;
1209     }
1210 
1211     /**
1212      * Write string to log file
1213      *
1214      * @param s is the string to write
1215      */
log(String s)1216     protected abstract void log(String s);
1217 
1218     /**
1219      * Write error string to log file.
1220      *
1221      * @param s is the string to write
1222      */
loge(String s)1223     protected abstract void loge(String s);
1224 
1225     /**
1226      * @return String array containing EHPLMNs associated with the card.
1227      */
getEhplmns()1228     public String[] getEhplmns() {
1229         return mEhplmns;
1230     }
1231 
1232     /**
1233      * @return String array containing PLMN from HplmnActRecord.
1234      */
getPlmnsFromHplmnActRecord()1235     public String[] getPlmnsFromHplmnActRecord() {
1236         if (mHplmnActRecords == null) return null;
1237         String[] hplmns = new String[mHplmnActRecords.length];
1238         for (int i = 0; i < mHplmnActRecords.length; i++) {
1239             hplmns[i] = mHplmnActRecords[i].plmn;
1240         }
1241         return hplmns;
1242     }
1243 
1244     /**
1245      * Return an interface to retrieve the ISIM records for IMS, if available.
1246      * @return the interface to retrieve the ISIM records, or null if not supported
1247      */
getIsimRecords()1248     public IsimRecords getIsimRecords() {
1249         return null;
1250     }
1251 
getUsimServiceTable()1252     public UsimServiceTable getUsimServiceTable() {
1253         return null;
1254     }
1255 
1256     /**
1257      * Solve authentication leakage issue. See b/147463955.
1258      * Returns the response of the SIM application on the UICC to authentication
1259      * challenge/response algorithm. The data string and challenge response are
1260      * Base64 encoded Strings.
1261      * Can support EAP-SIM, EAP-AKA with results encoded per 3GPP TS 31.102.
1262      *
1263      * @param authContext parameter P2 that specifies the authentication context
1264      * per 3GPP TS 31.102 (Section 7.1.2)
1265      * @param data authentication challenge data
1266      * @return challenge response
1267      */
1268     @Nullable
getIccSimChallengeResponse(int authContext, String data)1269     public String getIccSimChallengeResponse(int authContext, String data) {
1270         if (VDBG) log("getIccSimChallengeResponse:");
1271 
1272         //final here is for defensive copy.
1273         final CommandsInterface ci = mCi;
1274         final UiccCardApplication parentApp = mParentApp;
1275         if (ci == null || parentApp == null) {
1276             loge("getIccSimChallengeResponse: Fail, ci or parentApp is null");
1277             return null;
1278         }
1279 
1280         AuthAsyncResponse rsp = new AuthAsyncResponse();
1281 
1282         synchronized (rsp) {
1283             ci.requestIccSimAuthentication(authContext, data, parentApp.getAid(),
1284                     obtainMessage(EVENT_AKA_AUTHENTICATE_DONE, 0, 0, rsp));
1285             //TODO: factor wait with timeout into a separate method
1286             final long startTime = SystemClock.elapsedRealtime();
1287             do {
1288                 try {
1289                     long sleepTime = startTime + ICC_SIM_CHALLENGE_TIMEOUT_MILLIS
1290                             - SystemClock.elapsedRealtime();
1291                     if (sleepTime > 0) rsp.wait(sleepTime);
1292                 } catch (InterruptedException e) {
1293                     Rlog.w("IccRecords", "getIccSimChallengeResponse: InterruptedException.");
1294                 }
1295             } while (SystemClock.elapsedRealtime() - startTime < ICC_SIM_CHALLENGE_TIMEOUT_MILLIS
1296                     && rsp.authRsp == null && rsp.exception == null);
1297 
1298             if (SystemClock.elapsedRealtime() - startTime >= ICC_SIM_CHALLENGE_TIMEOUT_MILLIS
1299                     && rsp.authRsp == null && rsp.exception == null) {
1300                 loge("getIccSimChallengeResponse timeout!");
1301                 return null;
1302             }
1303 
1304             if (rsp.exception instanceof CommandException commandException) {
1305                 switch (commandException.getCommandError()) {
1306                     case REQUEST_NOT_SUPPORTED:
1307                         throw new UnsupportedOperationException(commandException);
1308                     default:
1309                         // handle other exceptions in the rsp.exception conditional below
1310                 }
1311             }
1312             if (rsp.exception != null) {
1313                 loge("getIccSimChallengeResponse exception: " + rsp.exception);
1314                 //TODO: propagate better exceptions up to the user now that we have them available
1315                 //in the call stack (see CommandException switch above).
1316                 return null;
1317             }
1318 
1319             if (rsp.authRsp == null) {
1320                 loge("getIccSimChallengeResponse: No authentication response");
1321                 return null;
1322             }
1323         }
1324         if (VDBG) log("getIccSimChallengeResponse: return rsp.authRsp");
1325 
1326         return rsp.authRsp.payload != null ? new String(rsp.authRsp.payload) : null;
1327     }
1328 
1329     /**
1330      * Convert the spn display condition to a bitmask
1331      * {@link com.android.internal.telephony.uicc.IccRecords.CarrierNameDisplayConditionBitmask}.
1332      *
1333      * b1 is the last bit of the display condition which is used to determine whether display of
1334      * PLMN network name is required when registered PLMN is **either** HPLMN or a PLMN in the
1335      * service provider PLMN list.
1336      *
1337      * b2 is the second last bit of the display condtion which is used to determine
1338      * whether display of Service Provider Name is required when registered PLMN is
1339      * **neither** HPLMN nor PLMN in the service provider PLMN list.
1340      *
1341      * Reference: 3GPP TS 31.102 section 4.2.12 EF_SPN
1342      *
1343      * @return a carrier name display condtion bitmask.
1344      */
1345     @CarrierNameDisplayConditionBitmask
convertSpnDisplayConditionToBitmask(int condition)1346     public static int convertSpnDisplayConditionToBitmask(int condition) {
1347         int carrierNameDisplayCondition = 0;
1348         // b1 = 0: display of registered PLMN name not required when registered PLMN is
1349         // either HPLMN or a PLMN in the service provider PLMN list.
1350         // b1 = 1: display of registered PLMN name required when registered PLMN is
1351         // either HPLMN or a PLMN in the service provider PLMN list.
1352         if ((condition & 0x1) == 0x1) {
1353             carrierNameDisplayCondition |= CARRIER_NAME_DISPLAY_CONDITION_BITMASK_PLMN;
1354         }
1355 
1356         // b2 = 0: display of the service provider name is **required** when registered
1357         // PLMN is neither HPLMN nor a PLMN in the service provider PLMN list.
1358         // b2 = 1: display of the servier provider name is **not required** when
1359         // registered PLMN is neither HPLMN nor PLMN in the service provider PLMN list.
1360         if ((condition & 0x2) == 0) {
1361             carrierNameDisplayCondition |= CARRIER_NAME_DISPLAY_CONDITION_BITMASK_SPN;
1362         }
1363 
1364         return carrierNameDisplayCondition;
1365     }
1366 
1367     /**
1368      * Get SMS capacity count on ICC card.
1369      */
getSmsCapacityOnIcc()1370     public int getSmsCapacityOnIcc() {
1371         if (DBG) log("getSmsCapacityOnIcc: " + mSmsCountOnIcc);
1372         return mSmsCountOnIcc;
1373     }
1374 
1375     /**
1376      * parse EF PSISMSC value [3GPP TS 31.102 Section 4.5.9]
1377      *
1378      * @param data read from EF PSISMSC field of type byte[]
1379      * @return SIP URI or tel URI of type string
1380      */
parseEfPsiSmsc(byte[] data)1381     protected String parseEfPsiSmsc(byte[] data) {
1382         SimTlv tlv = new SimTlv(data, 0, data.length);
1383         if (tlv.isValidObject() && tlv.getData() != null) {
1384             if (tlv.getTag() == TAG_TLV_USIM_VALUE_80) {
1385                 return new String(tlv.getData(), Charset.forName("UTF-8"));
1386             }
1387         }
1388         if (VDBG) {
1389             log("Can't find EF PSISMSC field in SIM = " + IccUtils.bytesToHexString(data));
1390         }
1391         return null;
1392     }
1393 
1394     /**
1395      * SMSC address read from the elementary file EF_PSISMSC
1396      *
1397      * @return SIP URI or tel URI of type string
1398      */
getSmscIdentity()1399     public String getSmscIdentity() {
1400         return mPsiSmsc;
1401     }
1402 
dump(FileDescriptor fd, PrintWriter pw, String[] args)1403     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1404         pw.println("IccRecords: " + this);
1405         pw.println(" mDestroyed=" + mDestroyed);
1406         pw.println(" mCi=" + mCi);
1407         pw.println(" mFh=" + mFh);
1408         pw.println(" mParentApp=" + mParentApp);
1409         pw.println(" recordsLoadedRegistrants: size=" + mRecordsLoadedRegistrants.size());
1410         for (int i = 0; i < mRecordsLoadedRegistrants.size(); i++) {
1411             pw.println("  recordsLoadedRegistrants[" + i + "]="
1412                     + ((Registrant)mRecordsLoadedRegistrants.get(i)).getHandler());
1413         }
1414         pw.println(" mLockedRecordsLoadedRegistrants: size="
1415                 + mLockedRecordsLoadedRegistrants.size());
1416         for (int i = 0; i < mLockedRecordsLoadedRegistrants.size(); i++) {
1417             pw.println("  mLockedRecordsLoadedRegistrants[" + i + "]="
1418                     + ((Registrant) mLockedRecordsLoadedRegistrants.get(i)).getHandler());
1419         }
1420         pw.println(" mNetworkLockedRecordsLoadedRegistrants: size="
1421                 + mNetworkLockedRecordsLoadedRegistrants.size());
1422         for (int i = 0; i < mNetworkLockedRecordsLoadedRegistrants.size(); i++) {
1423             pw.println("  mLockedRecordsLoadedRegistrants[" + i + "]="
1424                     + ((Registrant) mNetworkLockedRecordsLoadedRegistrants.get(i)).getHandler());
1425         }
1426         pw.println(" mImsiReadyRegistrants: size=" + mImsiReadyRegistrants.size());
1427         for (int i = 0; i < mImsiReadyRegistrants.size(); i++) {
1428             pw.println("  mImsiReadyRegistrants[" + i + "]="
1429                     + ((Registrant)mImsiReadyRegistrants.get(i)).getHandler());
1430         }
1431         pw.println(" mRecordsEventsRegistrants: size=" + mRecordsEventsRegistrants.size());
1432         for (int i = 0; i < mRecordsEventsRegistrants.size(); i++) {
1433             pw.println("  mRecordsEventsRegistrants[" + i + "]="
1434                     + ((Registrant)mRecordsEventsRegistrants.get(i)).getHandler());
1435         }
1436         pw.println(" mNewSmsRegistrants: size=" + mNewSmsRegistrants.size());
1437         for (int i = 0; i < mNewSmsRegistrants.size(); i++) {
1438             pw.println("  mNewSmsRegistrants[" + i + "]="
1439                     + ((Registrant)mNewSmsRegistrants.get(i)).getHandler());
1440         }
1441         pw.println(" mNetworkSelectionModeAutomaticRegistrants: size="
1442                 + mNetworkSelectionModeAutomaticRegistrants.size());
1443         for (int i = 0; i < mNetworkSelectionModeAutomaticRegistrants.size(); i++) {
1444             pw.println("  mNetworkSelectionModeAutomaticRegistrants[" + i + "]="
1445                     + ((Registrant)mNetworkSelectionModeAutomaticRegistrants.get(i)).getHandler());
1446         }
1447         pw.println(" mRecordsRequested=" + mRecordsRequested);
1448         pw.println(" mLockedRecordsReqReason=" + mLockedRecordsReqReason);
1449         pw.println(" mRecordsToLoad=" + mRecordsToLoad);
1450         pw.println(" mRdnCache=" + mAdnCache);
1451 
1452         String iccIdToPrint = SubscriptionInfo.getPrintableId(mFullIccId);
1453         pw.println(" iccid=" + iccIdToPrint);
1454         pw.println(" mMsisdn=" + Rlog.pii(VDBG, mMsisdn));
1455         pw.println(" mMsisdnTag=" + mMsisdnTag);
1456         pw.println(" mVoiceMailNum=" + Rlog.pii(VDBG, mVoiceMailNum));
1457         pw.println(" mVoiceMailTag=" + mVoiceMailTag);
1458         pw.println(" mNewVoiceMailNum=" + Rlog.pii(VDBG, mNewVoiceMailNum));
1459         pw.println(" mNewVoiceMailTag=" + mNewVoiceMailTag);
1460         pw.println(" mIsVoiceMailFixed=" + mIsVoiceMailFixed);
1461         pw.println(" mImsi=" + ((mImsi != null) ?
1462                 mImsi.substring(0, 6) + Rlog.pii(VDBG, mImsi.substring(6)) : "null"));
1463         if (mCarrierTestOverride.isInTestMode()) {
1464             pw.println(" mFakeImsi=" + mCarrierTestOverride.getFakeIMSI());
1465         }
1466         pw.println(" mMncLength=" + mMncLength);
1467         pw.println(" mMailboxIndex=" + mMailboxIndex);
1468         pw.println(" mSpn=" + mSpn);
1469         if (mCarrierTestOverride.isInTestMode()) {
1470             pw.println(" mFakeSpn=" + mCarrierTestOverride.getFakeSpn());
1471         }
1472         pw.flush();
1473     }
1474 
1475     /**
1476      * Get network name in PNN for the provided PLMN and LAC/TAC.
1477      *
1478      * @param opls OPL.
1479      * @param pnns PNN list.
1480      * @param plmn PLMN.
1481      * @param lacTac LAC/TAC
1482      * @return network Name for the provided PLMN and LAC/TAC.
1483      */
getNetworkNameForPlmnFromPnnOpl(PlmnNetworkName[] pnns, OperatorPlmnInfo[] opls, @Nullable String plmn, int lacTac)1484     @Nullable public static String getNetworkNameForPlmnFromPnnOpl(PlmnNetworkName[] pnns,
1485             OperatorPlmnInfo[] opls, @Nullable String plmn, int lacTac) {
1486         if (opls == null || pnns == null || plmn == null || plmn.length() < PLMN_MIN_LENGTH
1487                 || plmn.length() > PLMN_MAX_LENGTH) {
1488             return null;
1489         }
1490 
1491         for (OperatorPlmnInfo operatorPlmnInfo: opls) {
1492             int pnnIdx = operatorPlmnInfo.getPnnIdx(plmn, lacTac);
1493             if (pnnIdx >= 0) {
1494                 if (pnnIdx < pnns.length && pnns[pnnIdx] != null) {
1495                     return pnns[pnnIdx].getName();
1496                 } else {
1497                     Rlog.e("IccRecords", "Invalid PNN record for Record" + pnnIdx);
1498                     break;
1499                 }
1500             }
1501         }
1502         return null;
1503     }
1504 
1505     /**
1506      * Operator PLMN information. This contains the location area information or tracking area
1507      * that are used to associate a specific name contained in EF_PNN.
1508      *
1509      * Reference: 3GPP TS 31.102 section 4.2.59 EF_OPL
1510      */
1511     public static final class OperatorPlmnInfo {
1512         // PLMN numeric that may contains wildcard character "D".
1513         // A BCD value of 'D' in any of the MCC and/or MNC digits shall be used to indicate
1514         // a "wild" value for that corresponding MCC/MNC digit.
1515         // For example, the pattern "123DDD" could match all PLMN which mcc is 123.
1516         public final String plmnNumericPattern;
1517         public final int lacTacStart;
1518         public final int lacTacEnd;
1519         // Identifier of operator name in PNN to be displayed.
1520         // 0 indicates that the name is to be taken from other sources, see 3GPP TS 22.101.
1521         // pnnRecordId > 0 indicates record # (pnnRecordId - 1) in PNNs.
1522         public final int pnnRecordId;
1523 
OperatorPlmnInfo(@onNull String plmnNumericPattern, int lacTacStart, int lacTacEnd, int pnnRecordId)1524         public OperatorPlmnInfo(@NonNull String plmnNumericPattern, int lacTacStart, int lacTacEnd,
1525                                 int pnnRecordId) {
1526             this.plmnNumericPattern = plmnNumericPattern;
1527             this.lacTacStart = lacTacStart;
1528             this.lacTacEnd = lacTacEnd;
1529             this.pnnRecordId = pnnRecordId;
1530         }
1531 
1532         /**
1533          * Check whether provided plmn and lacTac matches the stored OperatorPlmnInfo.
1534          *
1535          * @return -1 if not matching.
1536          */
getPnnIdx(@ullable String plmn, int lacTac)1537         public int getPnnIdx(@Nullable String plmn, int lacTac) {
1538             if (plmn == null || plmn.length() != plmnNumericPattern.length()) return -1;
1539 
1540             // Check whether PLMN matches with the plmnNumericPattern
1541             // Character-by-character check is for performance reasons.
1542             for (int i = 0; i < plmn.length(); i++) {
1543                 if (plmn.charAt(i) != plmnNumericPattern.charAt(i)
1544                         && plmnNumericPattern.charAt(i) != 'D') {
1545                     return -1;
1546                 }
1547             }
1548             // As defiend in 3GPP TS 31.102 section 4.2.59 , lacTacStart = 0 and lacTacEnd = 0xFFFE
1549             // are used to indicate the entire range of LACs/TACs for the given PLMN.
1550             if (lacTacStart == 0 && lacTacEnd == 0xFFFE) {
1551                 return pnnRecordId - 1;
1552             }
1553             if (lacTac < lacTacStart || lacTac > lacTacEnd) return -1;
1554             return pnnRecordId - 1;
1555         }
1556 
1557         @Override
hashCode()1558         public int hashCode() {
1559             return Objects.hash(plmnNumericPattern, lacTacStart, lacTacEnd,
1560                     pnnRecordId);
1561         }
1562 
1563         @Override
equals(Object other)1564         public boolean equals(Object other) {
1565             if (this == other) return true;
1566             if (!(other instanceof OperatorPlmnInfo)) return false;
1567 
1568             OperatorPlmnInfo opi = (OperatorPlmnInfo) other;
1569             return TextUtils.equals(plmnNumericPattern, opi.plmnNumericPattern)
1570                     && lacTacStart == opi.lacTacStart
1571                     && lacTacEnd == opi.lacTacEnd
1572                     && pnnRecordId == opi.pnnRecordId;
1573         }
1574 
1575         @Override
toString()1576         public String toString() {
1577             return "{plmnNumericPattern = " + plmnNumericPattern + ", "
1578                     + "lacTacStart = " + lacTacStart + ", "
1579                     + "lacTacEnd = " + lacTacEnd + ", "
1580                     + "pnnRecordId = " + pnnRecordId
1581                     + "}";
1582         }
1583     }
1584 
1585     /**
1586      * Full and short version of PLMN network name.
1587      */
1588     public static final class PlmnNetworkName {
1589         public final String fullName;
1590         public final String shortName;
1591 
PlmnNetworkName(String fullName, String shortName)1592         public PlmnNetworkName(String fullName, String shortName) {
1593             this.fullName = fullName;
1594             this.shortName = shortName;
1595         }
1596 
1597         /**
1598          * Get the name stored in the PlmnNetworkName.
1599          * @return the full name if it's available; otherwise, short Name.
1600          */
getName()1601         @Nullable public String getName() {
1602             if (!TextUtils.isEmpty(fullName)) {
1603                 return fullName;
1604             } else {
1605                 return shortName;
1606             }
1607         }
1608 
1609         @Override
hashCode()1610         public int hashCode() {
1611             return Objects.hash(fullName, shortName);
1612         }
1613 
1614         @Override
equals(Object other)1615         public boolean equals(Object other) {
1616             if (this == other) return true;
1617             if (!(other instanceof PlmnNetworkName)) return false;
1618 
1619             PlmnNetworkName pnn = (PlmnNetworkName) other;
1620             return TextUtils.equals(fullName, pnn.fullName)
1621                     && TextUtils.equals(shortName, pnn.shortName);
1622         }
1623 
1624         @Override
toString()1625         public String toString() {
1626             return "{fullName = " + fullName + ", shortName = " + shortName + "}";
1627         }
1628     }
1629 
1630     /**
1631      * Sets the elementary (EF_SMSS) field with latest last used TP-Message reference value.
1632      * First byte of EF_SMSS represents the TPMR value as per the spec
1633      * (Section 4.2.9 of 3GPP TS 31.102)
1634      *
1635      * @param tpmr: Last used TP-Message reference parameter of type int
1636      * @param onComplete: android.os.Message to be notified upon completion
1637      */
setSmssTpmrValue(int tpmr, Message onComplete)1638     public void setSmssTpmrValue(int tpmr, Message onComplete) {
1639         if(VDBG) log("setSmssTpmrValue()");
1640         if (mSmssValues != null && mSmssValues.length > 0 && tpmr >= TPMR_MIN && tpmr <= TPMR_MAX) {
1641             byte[] tempSmss = mSmssValues.clone();
1642             tempSmss[0] = (byte) (tpmr & 0xFF);
1643             SmssRecord smssRecord = createSmssRecord(onComplete, tempSmss);
1644             mFh.updateEFTransparent(IccConstants.EF_SMSS, tempSmss,
1645                     obtainMessage(EVENT_SET_SMSS_RECORD_DONE, smssRecord));
1646         } else if (onComplete != null) {
1647             loge("Failed to set EF_SMSS [TPMR] field to SIM");
1648             if (mSmssValues == null || mSmssValues.length <= 0) {
1649                 AsyncResult.forMessage((onComplete)).exception =
1650                         new FileNotFoundException("EF_SMSS file not found");
1651             } else if (tpmr < TPMR_MIN || tpmr > TPMR_MAX) {
1652                 AsyncResult.forMessage((onComplete)).exception =
1653                         new IllegalArgumentException("TPMR value is not in allowed range");
1654             }
1655             onComplete.sendToTarget();
1656         }
1657     }
1658 
1659     /**
1660      * Fetches the last used TPMR value from elementary (EF_SMSS) field. First byte of EF_SMSS
1661      * represents the TPMR value as per the spec (Section 4.2.9 of 3GPP TS 31.102)
1662      *
1663      * @return TP-Message reference parameter of type int, -1 in case if it fails to read the
1664      * EF_SMSS field from the sim.
1665      */
getSmssTpmrValue()1666     public int getSmssTpmrValue() {
1667         if (mSmssValues != null && mSmssValues.length > 0) {
1668             return  (mSmssValues[0] & 0xFF);
1669         }
1670         loge("IccRecords - EF_SMSS is null");
1671         return SMSS_INVALID_TPMR;
1672     }
1673 
1674     @VisibleForTesting
createSmssRecord(Message msg, byte[] smss)1675     public SmssRecord createSmssRecord(Message msg, byte[] smss) {
1676         return new SmssRecord(msg, smss);
1677     }
1678 
1679 
1680     static class SmssRecord {
1681 
1682         private Message mMsg;
1683         private byte[] mSmss;
1684 
SmssRecord(Message msg, byte[] smss)1685         SmssRecord (Message msg, byte[] smss) {
1686             mMsg = msg;
1687             mSmss = smss;
1688         }
1689 
getSmssValue()1690         private byte[] getSmssValue() {
1691             return mSmss;
1692         }
1693 
getMessage()1694         private Message getMessage() {
1695             return mMsg;
1696         }
1697     }
1698 
loadFdnRecords()1699     public void loadFdnRecords() {
1700         if (mParentApp != null && mAdnCache != null) {
1701             log("Loading FdnRecords");
1702             mAdnCache.requestLoadAllAdnLike(IccConstants.EF_FDN, EF_EXT2,
1703                     obtainMessage(EVENT_GET_FDN_DONE));
1704         }
1705     }
1706 }
1707