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