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