1 /*
2  * Copyright (C) 2006, 2012 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 android.compat.annotation.UnsupportedAppUsage;
20 import android.content.Context;
21 import android.os.AsyncResult;
22 import android.os.Handler;
23 import android.os.Message;
24 import android.os.Registrant;
25 import android.os.RegistrantList;
26 
27 import com.android.internal.telephony.CommandException;
28 import com.android.internal.telephony.CommandsInterface;
29 import com.android.internal.telephony.PhoneConstants;
30 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppState;
31 import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
32 import com.android.internal.telephony.uicc.IccCardApplicationStatus.PersoSubState;
33 import com.android.internal.telephony.uicc.IccCardStatus.PinState;
34 import com.android.telephony.Rlog;
35 
36 import java.io.FileDescriptor;
37 import java.io.PrintWriter;
38 
39 /**
40  * {@hide}
41  */
42 public class UiccCardApplication {
43     private static final String LOG_TAG = "UiccCardApplication";
44     private static final boolean DBG = true;
45 
46     private static final int EVENT_PIN1_PUK1_DONE = 1;
47     private static final int EVENT_CHANGE_PIN1_DONE = 2;
48     private static final int EVENT_CHANGE_PIN2_DONE = 3;
49     private static final int EVENT_QUERY_FACILITY_FDN_DONE = 4;
50     private static final int EVENT_CHANGE_FACILITY_FDN_DONE = 5;
51     private static final int EVENT_QUERY_FACILITY_LOCK_DONE = 6;
52     private static final int EVENT_CHANGE_FACILITY_LOCK_DONE = 7;
53     private static final int EVENT_PIN2_PUK2_DONE = 8;
54     private static final int EVENT_RADIO_UNAVAILABLE = 9;
55 
56     /**
57      * These values are for authContext (parameter P2) per 3GPP TS 31.102 (Section 7.1.2)
58      */
59     public static final int AUTH_CONTEXT_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
60     public static final int AUTH_CONTEXT_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
61     public static final int AUTH_CONTEXT_UNDEFINED = PhoneConstants.AUTH_CONTEXT_UNDEFINED;
62 
63     @UnsupportedAppUsage
64     private final Object  mLock = new Object();
65     private UiccProfile   mUiccProfile; //parent
66     @UnsupportedAppUsage
67     private AppState      mAppState;
68     @UnsupportedAppUsage
69     private AppType       mAppType;
70     private int           mAuthContext;
71     @UnsupportedAppUsage
72     private PersoSubState mPersoSubState;
73     @UnsupportedAppUsage
74     private String        mAid;
75     private String        mAppLabel;
76     private boolean       mPin1Replaced;
77     @UnsupportedAppUsage
78     private PinState      mPin1State;
79     private PinState      mPin2State;
80     private boolean       mIccFdnEnabled;
81     private boolean       mDesiredFdnEnabled;
82     private boolean       mIccLockEnabled;
83     private boolean       mDesiredPinLocked;
84 
85     // App state will be ignored while deciding whether the card is ready or not.
86     private boolean       mIgnoreApp;
87     private boolean       mIccFdnAvailable = true; // Default is enabled.
88 
89     @UnsupportedAppUsage
90     private CommandsInterface mCi;
91     private Context mContext;
92     private IccRecords mIccRecords;
93     private IccFileHandler mIccFh;
94 
95     @UnsupportedAppUsage
96     private boolean mDestroyed;//set to true once this App is commanded to be disposed of.
97 
98     private RegistrantList mReadyRegistrants = new RegistrantList();
99     private RegistrantList mDetectedRegistrants = new RegistrantList();
100     private RegistrantList mPinLockedRegistrants = new RegistrantList();
101     private RegistrantList mNetworkLockedRegistrants = new RegistrantList();
102 
UiccCardApplication(UiccProfile uiccProfile, IccCardApplicationStatus as, Context c, CommandsInterface ci)103     public UiccCardApplication(UiccProfile uiccProfile,
104                         IccCardApplicationStatus as,
105                         Context c,
106                         CommandsInterface ci) {
107         if (DBG) log("Creating UiccApp: " + as);
108         mUiccProfile = uiccProfile;
109         mAppState = as.app_state;
110         mAppType = as.app_type;
111         mAuthContext = getAuthContext(mAppType);
112         mPersoSubState = as.perso_substate;
113         mAid = as.aid;
114         mAppLabel = as.app_label;
115         mPin1Replaced = (as.pin1_replaced != 0);
116         mPin1State = as.pin1;
117         mPin2State = as.pin2;
118         mIgnoreApp = false;
119 
120         mContext = c;
121         mCi = ci;
122 
123         mIccFh = createIccFileHandler(as.app_type);
124         mIccRecords = createIccRecords(as.app_type, mContext, mCi);
125         if (mAppState == AppState.APPSTATE_READY) {
126             queryFdn();
127             queryPin1State();
128         }
129         mCi.registerForNotAvailable(mHandler, EVENT_RADIO_UNAVAILABLE, null);
130     }
131 
132     @UnsupportedAppUsage
update(IccCardApplicationStatus as, Context c, CommandsInterface ci)133     public void update (IccCardApplicationStatus as, Context c, CommandsInterface ci) {
134         synchronized (mLock) {
135             if (mDestroyed) {
136                 loge("Application updated after destroyed! Fix me!");
137                 return;
138             }
139 
140             if (DBG) log(mAppType + " update. New " + as);
141             mContext = c;
142             mCi = ci;
143             AppType oldAppType = mAppType;
144             AppState oldAppState = mAppState;
145             PersoSubState oldPersoSubState = mPersoSubState;
146             PinState oldPin1State = mPin1State;
147             mAppType = as.app_type;
148             mAuthContext = getAuthContext(mAppType);
149             mAppState = as.app_state;
150             mPersoSubState = as.perso_substate;
151             mAid = as.aid;
152             mAppLabel = as.app_label;
153             mPin1Replaced = (as.pin1_replaced != 0);
154             mPin1State = as.pin1;
155             mPin2State = as.pin2;
156 
157             if (mAppType != oldAppType) {
158                 if (mIccFh != null) { mIccFh.dispose();}
159                 if (mIccRecords != null) { mIccRecords.dispose();}
160                 mIccFh = createIccFileHandler(as.app_type);
161                 mIccRecords = createIccRecords(as.app_type, c, ci);
162             }
163 
164             if (mPersoSubState != oldPersoSubState &&
165                     PersoSubState.isPersoLocked(mPersoSubState)) {
166                 notifyNetworkLockedRegistrantsIfNeeded(null);
167             }
168 
169             if (mAppState != oldAppState) {
170                 if (DBG) log(oldAppType + " changed state: " + oldAppState + " -> " + mAppState);
171                 // If the app state turns to APPSTATE_READY, then query FDN status,
172                 //as it might have failed in earlier attempt.
173                 if (mAppState == AppState.APPSTATE_READY) {
174                     queryFdn();
175                     queryPin1State();
176                 }
177                 notifyPinLockedRegistrantsIfNeeded(null);
178                 notifyReadyRegistrantsIfNeeded(null);
179                 notifyDetectedRegistrantsIfNeeded(null);
180             } else {
181                 if (mPin1State != oldPin1State)
182                     queryPin1State();
183             }
184         }
185     }
186 
187     @UnsupportedAppUsage
dispose()188     void dispose() {
189         synchronized (mLock) {
190             if (DBG) log(mAppType + " being Disposed");
191             mDestroyed = true;
192             if (mIccRecords != null) { mIccRecords.dispose();}
193             if (mIccFh != null) { mIccFh.dispose();}
194             mIccRecords = null;
195             mIccFh = null;
196             mCi.unregisterForNotAvailable(mHandler);
197         }
198     }
199 
createIccRecords(AppType type, Context c, CommandsInterface ci)200     private IccRecords createIccRecords(AppType type, Context c, CommandsInterface ci) {
201         if (type == AppType.APPTYPE_USIM || type == AppType.APPTYPE_SIM) {
202             return new SIMRecords(this, c, ci);
203         } else if (type == AppType.APPTYPE_RUIM || type == AppType.APPTYPE_CSIM){
204             return new RuimRecords(this, c, ci);
205         } else if (type == AppType.APPTYPE_ISIM) {
206             return new IsimUiccRecords(this, c, ci);
207         } else {
208             // Unknown app type (maybe detection is still in progress)
209             return null;
210         }
211     }
212 
createIccFileHandler(AppType type)213     private IccFileHandler createIccFileHandler(AppType type) {
214         switch (type) {
215             case APPTYPE_SIM:
216                 return new SIMFileHandler(this, mAid, mCi);
217             case APPTYPE_RUIM:
218                 return new RuimFileHandler(this, mAid, mCi);
219             case APPTYPE_USIM:
220                 return new UsimFileHandler(this, mAid, mCi);
221             case APPTYPE_CSIM:
222                 return new CsimFileHandler(this, mAid, mCi);
223             case APPTYPE_ISIM:
224                 return new IsimFileHandler(this, mAid, mCi);
225             default:
226                 return null;
227         }
228     }
229 
230     /** Assumes mLock is held. */
queryFdn()231     public void queryFdn() {
232         //This shouldn't change run-time. So needs to be called only once.
233         int serviceClassX;
234 
235         serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
236                         CommandsInterface.SERVICE_CLASS_DATA +
237                         CommandsInterface.SERVICE_CLASS_FAX;
238         mCi.queryFacilityLockForApp (
239                 CommandsInterface.CB_FACILITY_BA_FD, "", serviceClassX,
240                 mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_FDN_DONE));
241     }
242     /**
243      * Interpret EVENT_QUERY_FACILITY_LOCK_DONE
244      * @param ar is asyncResult of Query_Facility_Locked
245      */
onQueryFdnEnabled(AsyncResult ar)246     private void onQueryFdnEnabled(AsyncResult ar) {
247         synchronized (mLock) {
248             if (ar.exception != null) {
249                 if (DBG) log("Error in querying facility lock:" + ar.exception);
250                 return;
251             }
252 
253             int[] result = (int[])ar.result;
254             if(result.length != 0) {
255                 //0 - Available & Disabled, 1-Available & Enabled, 2-Unavailable.
256                 if (result[0] == 2) {
257                     mIccFdnEnabled = false;
258                     mIccFdnAvailable = false;
259                 } else {
260                     mIccFdnEnabled = (result[0] == 1) ? true : false;
261                     mIccFdnAvailable = true;
262                 }
263                 log("Query facility FDN : FDN service available: "+ mIccFdnAvailable
264                         +" enabled: "  + mIccFdnEnabled);
265             } else {
266                 loge("Bogus facility lock response");
267             }
268         }
269     }
270 
onChangeFdnDone(AsyncResult ar)271     private void onChangeFdnDone(AsyncResult ar) {
272         synchronized (mLock) {
273             int attemptsRemaining = -1;
274 
275             if (ar.exception == null) {
276                 mIccFdnEnabled = mDesiredFdnEnabled;
277                 if (DBG) log("EVENT_CHANGE_FACILITY_FDN_DONE: " +
278                         "mIccFdnEnabled=" + mIccFdnEnabled);
279             } else {
280                 attemptsRemaining = parsePinPukErrorResult(ar);
281                 loge("Error change facility fdn with exception " + ar.exception);
282             }
283             Message response = (Message)ar.userObj;
284             response.arg1 = attemptsRemaining;
285             AsyncResult.forMessage(response).exception = ar.exception;
286             response.sendToTarget();
287         }
288     }
289 
290     /** REMOVE when mIccLockEnabled is not needed, assumes mLock is held */
queryPin1State()291     private void queryPin1State() {
292         int serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
293                 CommandsInterface.SERVICE_CLASS_DATA +
294                 CommandsInterface.SERVICE_CLASS_FAX;
295         mCi.queryFacilityLockForApp (
296             CommandsInterface.CB_FACILITY_BA_SIM, "", serviceClassX,
297             mAid, mHandler.obtainMessage(EVENT_QUERY_FACILITY_LOCK_DONE));
298     }
299 
300     /** REMOVE when mIccLockEnabled is not needed*/
onQueryFacilityLock(AsyncResult ar)301     private void onQueryFacilityLock(AsyncResult ar) {
302         synchronized (mLock) {
303             if(ar.exception != null) {
304                 if (DBG) log("Error in querying facility lock:" + ar.exception);
305                 return;
306             }
307 
308             int[] ints = (int[])ar.result;
309             if(ints.length != 0) {
310                 if (DBG) log("Query facility lock : "  + ints[0]);
311 
312                 mIccLockEnabled = (ints[0] != 0);
313 
314                 // Correctness check: we expect mPin1State to match mIccLockEnabled.
315                 // When mPin1State is DISABLED mIccLockEanbled should be false.
316                 // When mPin1State is ENABLED mIccLockEnabled should be true.
317                 //
318                 // Here we validate these assumptions to assist in identifying which ril/radio's
319                 // have not correctly implemented GET_SIM_STATUS
320                 switch (mPin1State) {
321                     case PINSTATE_DISABLED:
322                         if (mIccLockEnabled) {
323                             loge("QUERY_FACILITY_LOCK:enabled GET_SIM_STATUS.Pin1:disabled."
324                                     + " Fixme");
325                         }
326                         break;
327                     case PINSTATE_ENABLED_NOT_VERIFIED:
328                     case PINSTATE_ENABLED_VERIFIED:
329                     case PINSTATE_ENABLED_BLOCKED:
330                     case PINSTATE_ENABLED_PERM_BLOCKED:
331                         if (!mIccLockEnabled) {
332                             loge("QUERY_FACILITY_LOCK:disabled GET_SIM_STATUS.Pin1:enabled."
333                                     + " Fixme");
334                         }
335                     case PINSTATE_UNKNOWN:
336                     default:
337                         if (DBG) log("Ignoring: pin1state=" + mPin1State);
338                         break;
339                 }
340             } else {
341                 loge("Bogus facility lock response");
342             }
343         }
344     }
345 
346     /** REMOVE when mIccLockEnabled is not needed */
onChangeFacilityLock(AsyncResult ar)347     private void onChangeFacilityLock(AsyncResult ar) {
348         synchronized (mLock) {
349             int attemptsRemaining = -1;
350 
351             if (ar.exception == null) {
352                 mIccLockEnabled = mDesiredPinLocked;
353                 if (DBG) log( "EVENT_CHANGE_FACILITY_LOCK_DONE: mIccLockEnabled= "
354                         + mIccLockEnabled);
355             } else {
356                 attemptsRemaining = parsePinPukErrorResult(ar);
357                 loge("Error change facility lock with exception " + ar.exception);
358             }
359             Message response = (Message)ar.userObj;
360             AsyncResult.forMessage(response).exception = ar.exception;
361             response.arg1 = attemptsRemaining;
362             response.sendToTarget();
363         }
364     }
365 
366     /**
367      * Parse the error response to obtain number of attempts remaining
368      */
parsePinPukErrorResult(AsyncResult ar)369     private int parsePinPukErrorResult(AsyncResult ar) {
370         int[] result = (int[]) ar.result;
371         if (result == null) {
372             return -1;
373         } else {
374             int length = result.length;
375             int attemptsRemaining = -1;
376             if (length > 0) {
377                 attemptsRemaining = result[0];
378             }
379             log("parsePinPukErrorResult: attemptsRemaining=" + attemptsRemaining);
380             return attemptsRemaining;
381         }
382     }
383 
384     private Handler mHandler = new Handler() {
385         @Override
386         public void handleMessage(Message msg){
387             AsyncResult ar;
388 
389             if (mDestroyed) {
390                 loge("Received message " + msg + "[" + msg.what
391                         + "] while being destroyed. Ignoring.");
392                 //When UiccCardApp dispose,unlock SIM PIN message and need return exception.
393                 if (msg.what == EVENT_PIN1_PUK1_DONE) {
394                     ar = (AsyncResult) msg.obj;
395                     if (ar != null) {
396                         ar.exception = new CommandException(CommandException.Error.ABORTED);
397                         Message response = (Message) ar.userObj;
398                         if (response != null) {
399                             AsyncResult.forMessage(response).exception = ar.exception;
400                             response.sendToTarget();
401                         }
402                     }
403                 }
404                 return;
405             }
406 
407             switch (msg.what) {
408                 case EVENT_PIN1_PUK1_DONE:
409                 case EVENT_PIN2_PUK2_DONE:
410                 case EVENT_CHANGE_PIN1_DONE:
411                 case EVENT_CHANGE_PIN2_DONE:
412                     // a PIN/PUK/PIN2/PUK2 complete
413                     // request has completed. ar.userObj is the response Message
414                     ar = (AsyncResult)msg.obj;
415                     int attemptsRemaining = parsePinPukErrorResult(ar);
416                     Message response = (Message)ar.userObj;
417                     AsyncResult.forMessage(response).exception = ar.exception;
418                     response.arg1 = attemptsRemaining;
419                     response.sendToTarget();
420                     break;
421                 case EVENT_QUERY_FACILITY_FDN_DONE:
422                     ar = (AsyncResult)msg.obj;
423                     onQueryFdnEnabled(ar);
424                     break;
425                 case EVENT_CHANGE_FACILITY_FDN_DONE:
426                     ar = (AsyncResult)msg.obj;
427                     onChangeFdnDone(ar);
428                     break;
429                 case EVENT_QUERY_FACILITY_LOCK_DONE:
430                     ar = (AsyncResult)msg.obj;
431                     onQueryFacilityLock(ar);
432                     break;
433                 case EVENT_CHANGE_FACILITY_LOCK_DONE:
434                     ar = (AsyncResult)msg.obj;
435                     onChangeFacilityLock(ar);
436                     break;
437                 case EVENT_RADIO_UNAVAILABLE:
438                     if (DBG) log("handleMessage (EVENT_RADIO_UNAVAILABLE)");
439                     mAppState = AppState.APPSTATE_UNKNOWN;
440                     break;
441                 default:
442                     loge("Unknown Event " + msg.what);
443             }
444         }
445     };
446 
447     @UnsupportedAppUsage
registerForReady(Handler h, int what, Object obj)448     public void registerForReady(Handler h, int what, Object obj) {
449         synchronized (mLock) {
450             Registrant r = new Registrant (h, what, obj);
451             mReadyRegistrants.add(r);
452             notifyReadyRegistrantsIfNeeded(r);
453         }
454     }
455 
456     @UnsupportedAppUsage
unregisterForReady(Handler h)457     public void unregisterForReady(Handler h) {
458         synchronized (mLock) {
459             mReadyRegistrants.remove(h);
460         }
461     }
462 
registerForDetected(Handler h, int what, Object obj)463     public void registerForDetected(Handler h, int what, Object obj) {
464         synchronized (mLock) {
465             Registrant r = new Registrant(h, what, obj);
466             mDetectedRegistrants.add(r);
467             notifyDetectedRegistrantsIfNeeded(r);
468         }
469     }
470 
unregisterForDetected(Handler h)471     public void unregisterForDetected(Handler h) {
472         synchronized (mLock) {
473             mDetectedRegistrants.remove(h);
474         }
475     }
476 
477     /**
478      * Notifies handler of any transition into State.isPinLocked()
479      */
registerForLocked(Handler h, int what, Object obj)480     protected void registerForLocked(Handler h, int what, Object obj) {
481         synchronized (mLock) {
482             Registrant r = new Registrant (h, what, obj);
483             mPinLockedRegistrants.add(r);
484             notifyPinLockedRegistrantsIfNeeded(r);
485         }
486     }
487 
unregisterForLocked(Handler h)488     protected void unregisterForLocked(Handler h) {
489         synchronized (mLock) {
490             mPinLockedRegistrants.remove(h);
491         }
492     }
493 
494     /**
495      * Notifies handler of any transition into State.NETWORK_LOCKED
496      */
registerForNetworkLocked(Handler h, int what, Object obj)497     protected void registerForNetworkLocked(Handler h, int what, Object obj) {
498         synchronized (mLock) {
499             Registrant r = new Registrant (h, what, obj);
500             mNetworkLockedRegistrants.add(r);
501             notifyNetworkLockedRegistrantsIfNeeded(r);
502         }
503     }
504 
unregisterForNetworkLocked(Handler h)505     protected void unregisterForNetworkLocked(Handler h) {
506         synchronized (mLock) {
507             mNetworkLockedRegistrants.remove(h);
508         }
509     }
510 
511     /**
512      * Notifies specified registrant, assume mLock is held.
513      *
514      * @param r Registrant to be notified. If null - all registrants will be notified
515      */
notifyReadyRegistrantsIfNeeded(Registrant r)516     private void notifyReadyRegistrantsIfNeeded(Registrant r) {
517         if (mDestroyed) {
518             return;
519         }
520         if (mAppState == AppState.APPSTATE_READY) {
521             if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
522                     mPin1State == PinState.PINSTATE_ENABLED_BLOCKED ||
523                     mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
524                 loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
525                 // Don't notify if application is in an invalid state
526                 return;
527             }
528             if (r == null) {
529                 if (DBG) log("Notifying registrants: READY");
530                 mReadyRegistrants.notifyRegistrants();
531             } else {
532                 if (DBG) log("Notifying 1 registrant: READY");
533                 r.notifyRegistrant(new AsyncResult(null, null, null));
534             }
535         }
536     }
537 
538     /**
539      * Notifies specified registrant, assume mLock is held.
540      *
541      * @param r Registrant to be notified. If null - all registrants will be notified
542      */
notifyDetectedRegistrantsIfNeeded(Registrant r)543     private void notifyDetectedRegistrantsIfNeeded(Registrant r) {
544         if (mDestroyed) {
545             return;
546         }
547         if (mAppState == AppState.APPSTATE_DETECTED) {
548             if (r == null) {
549                 if (DBG) log("Notifying registrants: DETECTED");
550                 mDetectedRegistrants.notifyRegistrants();
551             } else {
552                 if (DBG) log("Notifying 1 registrant: DETECTED");
553                 r.notifyRegistrant(new AsyncResult(null, null, null));
554             }
555         }
556     }
557 
558     /**
559      * Notifies specified registrant, assume mLock is held.
560      *
561      * @param r Registrant to be notified. If null - all registrants will be notified
562      */
notifyPinLockedRegistrantsIfNeeded(Registrant r)563     private void notifyPinLockedRegistrantsIfNeeded(Registrant r) {
564         if (mDestroyed) {
565             return;
566         }
567 
568         if (mAppState == AppState.APPSTATE_PIN ||
569                 mAppState == AppState.APPSTATE_PUK) {
570             if (mPin1State == PinState.PINSTATE_ENABLED_VERIFIED ||
571                     mPin1State == PinState.PINSTATE_DISABLED) {
572                 loge("Sanity check failed! APPSTATE is locked while PIN1 is not!!!");
573                 //Don't notify if application is in an invalid state
574                 return;
575             }
576             if (r == null) {
577                 if (DBG) log("Notifying registrants: LOCKED");
578                 mPinLockedRegistrants.notifyRegistrants();
579             } else {
580                 if (DBG) log("Notifying 1 registrant: LOCKED");
581                 r.notifyRegistrant(new AsyncResult(null, null, null));
582             }
583         }
584     }
585 
586     /**
587      * Notifies specified registrant, assume mLock is held.
588      *
589      * @param r Registrant to be notified. If null - all registrants will be notified
590      */
notifyNetworkLockedRegistrantsIfNeeded(Registrant r)591     private void notifyNetworkLockedRegistrantsIfNeeded(Registrant r) {
592         if (mDestroyed) {
593             return;
594         }
595 
596         if (mAppState == AppState.APPSTATE_SUBSCRIPTION_PERSO &&
597                 PersoSubState.isPersoLocked(mPersoSubState)) {
598             AsyncResult ar = new AsyncResult(null, mPersoSubState.ordinal(), null);
599             if (r == null) {
600                 if (DBG) log("Notifying registrants: NETWORK_LOCKED with mPersoSubState" + mPersoSubState);
601                 mNetworkLockedRegistrants.notifyRegistrants(ar);
602             } else {
603                 if (DBG) log("Notifying 1 registrant: NETWORK_LOCKED with mPersoSubState" + mPersoSubState);
604                 r.notifyRegistrant(ar);
605             }
606         }
607     }
608 
609     @UnsupportedAppUsage
getState()610     public AppState getState() {
611         synchronized (mLock) {
612             return mAppState;
613         }
614     }
615 
616     @UnsupportedAppUsage
getType()617     public AppType getType() {
618         synchronized (mLock) {
619             return mAppType;
620         }
621     }
622 
623     @UnsupportedAppUsage
getAuthContext()624     public int getAuthContext() {
625         synchronized (mLock) {
626             return mAuthContext;
627         }
628     }
629 
630     /**
631      * Returns the authContext based on the type of UiccCard.
632      *
633      * @param appType the app type
634      * @return authContext corresponding to the type or AUTH_CONTEXT_UNDEFINED if appType not
635      * supported
636      */
getAuthContext(AppType appType)637     private static int getAuthContext(AppType appType) {
638         int authContext;
639 
640         switch (appType) {
641             case APPTYPE_SIM:
642                 authContext = AUTH_CONTEXT_EAP_SIM;
643                 break;
644 
645             case APPTYPE_USIM:
646                 authContext = AUTH_CONTEXT_EAP_AKA;
647                 break;
648 
649             default:
650                 authContext = AUTH_CONTEXT_UNDEFINED;
651                 break;
652         }
653 
654         return authContext;
655     }
656 
657     @UnsupportedAppUsage
getPersoSubState()658     public PersoSubState getPersoSubState() {
659         synchronized (mLock) {
660             return mPersoSubState;
661         }
662     }
663 
664     @UnsupportedAppUsage
getAid()665     public String getAid() {
666         synchronized (mLock) {
667             return mAid;
668         }
669     }
670 
getAppLabel()671     public String getAppLabel() {
672         return mAppLabel;
673     }
674 
675     @UnsupportedAppUsage
getPin1State()676     public PinState getPin1State() {
677         synchronized (mLock) {
678             if (mPin1Replaced) {
679                 return mUiccProfile.getUniversalPinState();
680             }
681             return mPin1State;
682         }
683     }
684 
685     @UnsupportedAppUsage
getIccFileHandler()686     public IccFileHandler getIccFileHandler() {
687         synchronized (mLock) {
688             return mIccFh;
689         }
690     }
691 
692     @UnsupportedAppUsage
getIccRecords()693     public IccRecords getIccRecords() {
694         synchronized (mLock) {
695             return mIccRecords;
696         }
697     }
698 
699     /**
700      * Supply the ICC PIN to the ICC
701      *
702      * When the operation is complete, onComplete will be sent to its
703      * Handler.
704      *
705      * onComplete.obj will be an AsyncResult
706      * onComplete.arg1 = remaining attempts before puk locked or -1 if unknown
707      *
708      * ((AsyncResult)onComplete.obj).exception == null on success
709      * ((AsyncResult)onComplete.obj).exception != null on fail
710      *
711      * If the supplied PIN is incorrect:
712      * ((AsyncResult)onComplete.obj).exception != null
713      * && ((AsyncResult)onComplete.obj).exception
714      *       instanceof com.android.internal.telephony.gsm.CommandException)
715      * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
716      *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
717      */
supplyPin(String pin, Message onComplete)718     public void supplyPin (String pin, Message onComplete) {
719         synchronized (mLock) {
720             mCi.supplyIccPinForApp(pin, mAid, mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE,
721                     onComplete));
722         }
723     }
724 
725     /**
726      * Supply the ICC PUK to the ICC
727      *
728      * When the operation is complete, onComplete will be sent to its
729      * Handler.
730      *
731      * onComplete.obj will be an AsyncResult
732      * onComplete.arg1 = remaining attempts before Icc will be permanently unusable
733      * or -1 if unknown
734      *
735      * ((AsyncResult)onComplete.obj).exception == null on success
736      * ((AsyncResult)onComplete.obj).exception != null on fail
737      *
738      * If the supplied PIN is incorrect:
739      * ((AsyncResult)onComplete.obj).exception != null
740      * && ((AsyncResult)onComplete.obj).exception
741      *       instanceof com.android.internal.telephony.gsm.CommandException)
742      * && ((CommandException)(((AsyncResult)onComplete.obj).exception))
743      *          .getCommandError() == CommandException.Error.PASSWORD_INCORRECT
744      *
745      *
746      */
supplyPuk(String puk, String newPin, Message onComplete)747     public void supplyPuk (String puk, String newPin, Message onComplete) {
748         synchronized (mLock) {
749         mCi.supplyIccPukForApp(puk, newPin, mAid,
750                 mHandler.obtainMessage(EVENT_PIN1_PUK1_DONE, onComplete));
751         }
752     }
753 
supplyPin2(String pin2, Message onComplete)754     public void supplyPin2 (String pin2, Message onComplete) {
755         synchronized (mLock) {
756             mCi.supplyIccPin2ForApp(pin2, mAid,
757                     mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
758         }
759     }
760 
supplyPuk2(String puk2, String newPin2, Message onComplete)761     public void supplyPuk2 (String puk2, String newPin2, Message onComplete) {
762         synchronized (mLock) {
763             mCi.supplyIccPuk2ForApp(puk2, newPin2, mAid,
764                     mHandler.obtainMessage(EVENT_PIN2_PUK2_DONE, onComplete));
765         }
766     }
767 
supplyNetworkDepersonalization(String pin, Message onComplete)768     public void supplyNetworkDepersonalization (String pin, Message onComplete) {
769         synchronized (mLock) {
770             if (DBG) log("supplyNetworkDepersonalization");
771             mCi.supplyNetworkDepersonalization(pin, onComplete);
772         }
773     }
774 
supplySimDepersonalization(PersoSubState persoType, String pin, Message onComplete)775     public void supplySimDepersonalization(PersoSubState persoType,
776                                            String pin, Message onComplete) {
777         synchronized (mLock) {
778             if (DBG) log("supplySimDepersonalization");
779             mCi.supplySimDepersonalization(persoType, pin, onComplete);
780         }
781     }
782 
783     /**
784      * Check whether ICC pin lock is enabled
785      * This is a sync call which returns the cached pin enabled state
786      *
787      * @return true for ICC locked enabled
788      *         false for ICC locked disabled
789      */
getIccLockEnabled()790     public boolean getIccLockEnabled() {
791         return mIccLockEnabled;
792         /* STOPSHIP: Remove line above and all code associated with setting
793            mIccLockEanbled once all RIL correctly sends the pin1 state.
794         // Use getPin1State to take into account pin1Replaced flag
795         PinState pinState = getPin1State();
796         return pinState == PinState.PINSTATE_ENABLED_NOT_VERIFIED ||
797                pinState == PinState.PINSTATE_ENABLED_VERIFIED ||
798                pinState == PinState.PINSTATE_ENABLED_BLOCKED ||
799                pinState == PinState.PINSTATE_ENABLED_PERM_BLOCKED;*/
800      }
801 
802     /**
803      * Check whether ICC fdn (fixed dialing number) is enabled
804      * This is a sync call which returns the cached pin enabled state
805      *
806      * @return true for ICC fdn enabled
807      *         false for ICC fdn disabled
808      */
getIccFdnEnabled()809     public boolean getIccFdnEnabled() {
810         synchronized (mLock) {
811             return mIccFdnEnabled;
812         }
813     }
814 
815     /**
816      * Check whether fdn (fixed dialing number) service is available.
817      * @return true if ICC fdn service available
818      *         false if ICC fdn service not available
819      */
getIccFdnAvailable()820     public boolean getIccFdnAvailable() {
821         return mIccFdnAvailable;
822     }
823 
824     /**
825      * Set the ICC pin lock enabled or disabled
826      * When the operation is complete, onComplete will be sent to its handler
827      *
828      * @param enabled "true" for locked "false" for unlocked.
829      * @param password needed to change the ICC pin state, aka. Pin1
830      * @param onComplete
831      *        onComplete.obj will be an AsyncResult
832      *        ((AsyncResult)onComplete.obj).exception == null on success
833      *        ((AsyncResult)onComplete.obj).exception != null on fail
834      */
setIccLockEnabled(boolean enabled, String password, Message onComplete)835     public void setIccLockEnabled (boolean enabled,
836             String password, Message onComplete) {
837         synchronized (mLock) {
838             int serviceClassX;
839             serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
840                     CommandsInterface.SERVICE_CLASS_DATA +
841                     CommandsInterface.SERVICE_CLASS_FAX;
842 
843             mDesiredPinLocked = enabled;
844 
845             mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_SIM,
846                     enabled, password, serviceClassX, mAid,
847                     mHandler.obtainMessage(EVENT_CHANGE_FACILITY_LOCK_DONE, onComplete));
848         }
849     }
850 
851     /**
852      * Set the ICC fdn enabled or disabled
853      * When the operation is complete, onComplete will be sent to its handler
854      *
855      * @param enabled "true" for locked "false" for unlocked.
856      * @param password needed to change the ICC fdn enable, aka Pin2
857      * @param onComplete
858      *        onComplete.obj will be an AsyncResult
859      *        ((AsyncResult)onComplete.obj).exception == null on success
860      *        ((AsyncResult)onComplete.obj).exception != null on fail
861      */
setIccFdnEnabled(boolean enabled, String password, Message onComplete)862     public void setIccFdnEnabled (boolean enabled,
863             String password, Message onComplete) {
864         synchronized (mLock) {
865             int serviceClassX;
866             serviceClassX = CommandsInterface.SERVICE_CLASS_VOICE +
867                     CommandsInterface.SERVICE_CLASS_DATA +
868                     CommandsInterface.SERVICE_CLASS_FAX +
869                     CommandsInterface.SERVICE_CLASS_SMS;
870 
871             mDesiredFdnEnabled = enabled;
872 
873             mCi.setFacilityLockForApp(CommandsInterface.CB_FACILITY_BA_FD,
874                     enabled, password, serviceClassX, mAid,
875                     mHandler.obtainMessage(EVENT_CHANGE_FACILITY_FDN_DONE, onComplete));
876         }
877     }
878 
879     /**
880      * Change the ICC password used in ICC pin lock
881      * When the operation is complete, onComplete will be sent to its handler
882      *
883      * @param oldPassword is the old password
884      * @param newPassword is the new password
885      * @param onComplete
886      *        onComplete.obj will be an AsyncResult
887      *        onComplete.arg1 = attempts remaining or -1 if unknown
888      *        ((AsyncResult)onComplete.obj).exception == null on success
889      *        ((AsyncResult)onComplete.obj).exception != null on fail
890      */
changeIccLockPassword(String oldPassword, String newPassword, Message onComplete)891     public void changeIccLockPassword(String oldPassword, String newPassword,
892             Message onComplete) {
893         synchronized (mLock) {
894             if (DBG) log("changeIccLockPassword");
895             mCi.changeIccPinForApp(oldPassword, newPassword, mAid,
896                     mHandler.obtainMessage(EVENT_CHANGE_PIN1_DONE, onComplete));
897         }
898     }
899 
900     /**
901      * Change the ICC password used in ICC fdn enable
902      * When the operation is complete, onComplete will be sent to its handler
903      *
904      * @param oldPassword is the old password
905      * @param newPassword is the new password
906      * @param onComplete
907      *        onComplete.obj will be an AsyncResult
908      *        ((AsyncResult)onComplete.obj).exception == null on success
909      *        ((AsyncResult)onComplete.obj).exception != null on fail
910      */
changeIccFdnPassword(String oldPassword, String newPassword, Message onComplete)911     public void changeIccFdnPassword(String oldPassword, String newPassword,
912             Message onComplete) {
913         synchronized (mLock) {
914             if (DBG) log("changeIccFdnPassword");
915             mCi.changeIccPin2ForApp(oldPassword, newPassword, mAid,
916                     mHandler.obtainMessage(EVENT_CHANGE_PIN2_DONE, onComplete));
917         }
918     }
919 
920     /**
921      * @return true if the UiccCardApplication is ready.
922      */
isReady()923     public boolean isReady() {
924         synchronized (mLock) {
925             if (mAppState != AppState.APPSTATE_READY) {
926                 return false;
927             } else if (mPin1State == PinState.PINSTATE_ENABLED_NOT_VERIFIED
928                     || mPin1State == PinState.PINSTATE_ENABLED_BLOCKED
929                     || mPin1State == PinState.PINSTATE_ENABLED_PERM_BLOCKED) {
930                 loge("Sanity check failed! APPSTATE is ready while PIN1 is not verified!!!");
931                 return false;
932             } else {
933                 return true;
934             }
935         }
936     }
937 
938     /**
939      * @return true if ICC card is PIN2 blocked
940      */
getIccPin2Blocked()941     public boolean getIccPin2Blocked() {
942         synchronized (mLock) {
943             return mPin2State == PinState.PINSTATE_ENABLED_BLOCKED;
944         }
945     }
946 
947     /**
948      * @return true if ICC card is PUK2 blocked
949      */
getIccPuk2Blocked()950     public boolean getIccPuk2Blocked() {
951         synchronized (mLock) {
952             return mPin2State == PinState.PINSTATE_ENABLED_PERM_BLOCKED;
953         }
954     }
955 
956     @UnsupportedAppUsage
getPhoneId()957     public int getPhoneId() {
958         return mUiccProfile.getPhoneId();
959     }
960 
isAppIgnored()961     public boolean isAppIgnored() {
962         return mIgnoreApp;
963     }
964 
setAppIgnoreState(boolean ignore)965     public void setAppIgnoreState(boolean ignore) {
966         mIgnoreApp = ignore;
967     }
968 
getUiccProfile()969     protected UiccProfile getUiccProfile() {
970         return mUiccProfile;
971     }
972 
973     @UnsupportedAppUsage
log(String msg)974     private void log(String msg) {
975         Rlog.d(LOG_TAG, msg);
976     }
977 
978     @UnsupportedAppUsage
loge(String msg)979     private void loge(String msg) {
980         Rlog.e(LOG_TAG, msg);
981     }
982 
dump(FileDescriptor fd, PrintWriter pw, String[] args)983     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
984         pw.println("UiccCardApplication: " + this);
985         pw.println(" mUiccProfile=" + mUiccProfile);
986         pw.println(" mAppState=" + mAppState);
987         pw.println(" mAppType=" + mAppType);
988         pw.println(" mPersoSubState=" + mPersoSubState);
989         pw.println(" mAid=" + mAid);
990         pw.println(" mAppLabel=" + mAppLabel);
991         pw.println(" mPin1Replaced=" + mPin1Replaced);
992         pw.println(" mPin1State=" + mPin1State);
993         pw.println(" mPin2State=" + mPin2State);
994         pw.println(" mIccFdnEnabled=" + mIccFdnEnabled);
995         pw.println(" mDesiredFdnEnabled=" + mDesiredFdnEnabled);
996         pw.println(" mIccLockEnabled=" + mIccLockEnabled);
997         pw.println(" mDesiredPinLocked=" + mDesiredPinLocked);
998         pw.println(" mCi=" + mCi);
999         pw.println(" mIccRecords=" + mIccRecords);
1000         pw.println(" mIccFh=" + mIccFh);
1001         pw.println(" mDestroyed=" + mDestroyed);
1002         pw.println(" mReadyRegistrants: size=" + mReadyRegistrants.size());
1003         for (int i = 0; i < mReadyRegistrants.size(); i++) {
1004             pw.println("  mReadyRegistrants[" + i + "]="
1005                     + ((Registrant)mReadyRegistrants.get(i)).getHandler());
1006         }
1007         pw.println(" mPinLockedRegistrants: size=" + mPinLockedRegistrants.size());
1008         for (int i = 0; i < mPinLockedRegistrants.size(); i++) {
1009             pw.println("  mPinLockedRegistrants[" + i + "]="
1010                     + ((Registrant)mPinLockedRegistrants.get(i)).getHandler());
1011         }
1012         pw.println(" mNetworkLockedRegistrants: size=" + mNetworkLockedRegistrants.size());
1013         for (int i = 0; i < mNetworkLockedRegistrants.size(); i++) {
1014             pw.println("  mNetworkLockedRegistrants[" + i + "]="
1015                     + ((Registrant)mNetworkLockedRegistrants.get(i)).getHandler());
1016         }
1017         pw.flush();
1018     }
1019 }
1020