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