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