1 /*
2  * Copyright (C) 2008 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.os.AsyncResult;
21 import android.os.Build;
22 import android.os.Handler;
23 import android.os.Message;
24 
25 import com.android.internal.telephony.CommandsInterface;
26 
27 import java.util.ArrayList;
28 
29 /**
30  * {@hide}
31  */
32 public abstract class IccFileHandler extends Handler implements IccConstants {
33     private static final boolean VDBG = false;
34 
35     //from TS 11.11 9.1 or elsewhere
36     static protected final int COMMAND_READ_BINARY = 0xb0;
37     static protected final int COMMAND_UPDATE_BINARY = 0xd6;
38     static protected final int COMMAND_READ_RECORD = 0xb2;
39     static protected final int COMMAND_UPDATE_RECORD = 0xdc;
40     static protected final int COMMAND_SEEK = 0xa2;
41     static protected final int COMMAND_GET_RESPONSE = 0xc0;
42 
43     // from TS 11.11 9.2.5
44     static protected final int READ_RECORD_MODE_ABSOLUTE = 4;
45 
46     //***** types of files  TS 11.11 9.3
47     static protected final int EF_TYPE_TRANSPARENT = 0;
48     static protected final int EF_TYPE_LINEAR_FIXED = 1;
49     static protected final int EF_TYPE_CYCLIC = 3;
50 
51     //***** types of files  TS 11.11 9.3
52     static protected final int TYPE_RFU = 0;
53     static protected final int TYPE_MF  = 1;
54     static protected final int TYPE_DF  = 2;
55     static protected final int TYPE_EF  = 4;
56 
57     // size of GET_RESPONSE for EF's
58     static protected final int GET_RESPONSE_EF_SIZE_BYTES = 15;
59     static protected final int GET_RESPONSE_EF_IMG_SIZE_BYTES = 10;
60 
61     // Byte order received in response to COMMAND_GET_RESPONSE
62     // Refer TS 51.011 Section 9.2.1
63     static protected final int RESPONSE_DATA_RFU_1 = 0;
64     static protected final int RESPONSE_DATA_RFU_2 = 1;
65 
66     static protected final int RESPONSE_DATA_FILE_SIZE_1 = 2;
67     static protected final int RESPONSE_DATA_FILE_SIZE_2 = 3;
68 
69     static protected final int RESPONSE_DATA_FILE_ID_1 = 4;
70     static protected final int RESPONSE_DATA_FILE_ID_2 = 5;
71     static protected final int RESPONSE_DATA_FILE_TYPE = 6;
72     static protected final int RESPONSE_DATA_RFU_3 = 7;
73     static protected final int RESPONSE_DATA_ACCESS_CONDITION_1 = 8;
74     static protected final int RESPONSE_DATA_ACCESS_CONDITION_2 = 9;
75     static protected final int RESPONSE_DATA_ACCESS_CONDITION_3 = 10;
76     static protected final int RESPONSE_DATA_FILE_STATUS = 11;
77     static protected final int RESPONSE_DATA_LENGTH = 12;
78     static protected final int RESPONSE_DATA_STRUCTURE = 13;
79     static protected final int RESPONSE_DATA_RECORD_LENGTH = 14;
80 
81 
82     //***** Events
83 
84     /** Finished retrieving size of transparent EF; start loading. */
85     static protected final int EVENT_GET_BINARY_SIZE_DONE = 4;
86     /** Finished loading contents of transparent EF; post result. */
87     static protected final int EVENT_READ_BINARY_DONE = 5;
88     /** Finished retrieving size of records for linear-fixed EF; now load. */
89     static protected final int EVENT_GET_RECORD_SIZE_DONE = 6;
90     /** Finished loading single record from a linear-fixed EF; post result. */
91     static protected final int EVENT_READ_RECORD_DONE = 7;
92     /** Finished retrieving record size; post result. */
93     static protected final int EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE = 8;
94     /** Finished retrieving image instance record; post result. */
95     static protected final int EVENT_READ_IMG_DONE = 9;
96     /** Finished retrieving icon data; post result. */
97     static protected final int EVENT_READ_ICON_DONE = 10;
98     /** Finished retrieving size of record for EFimg now. */
99     static protected final int EVENT_GET_RECORD_SIZE_IMG_DONE = 11;
100     /** Finished retriveing record size of transparent file. */
101     protected static final int EVENT_GET_EF_TRANSPARENT_SIZE_DONE = 12;
102 
103      // member variables
104     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
105     protected final CommandsInterface mCi;
106     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
107     protected final UiccCardApplication mParentApp;
108     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
109     protected final String mAid;
110 
111     static class LoadLinearFixedContext {
112 
113         int mEfid;
114         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
115         int mRecordNum, mRecordSize, mCountRecords;
116         boolean mLoadAll;
117         String mPath;
118 
119         Message mOnLoaded;
120 
121         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
122         ArrayList<byte[]> results;
123 
124         @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
LoadLinearFixedContext(int efid, int recordNum, Message onLoaded)125         LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) {
126             mEfid = efid;
127             mRecordNum = recordNum;
128             mOnLoaded = onLoaded;
129             mLoadAll = false;
130             mPath = null;
131         }
132 
LoadLinearFixedContext(int efid, int recordNum, String path, Message onLoaded)133         LoadLinearFixedContext(int efid, int recordNum, String path, Message onLoaded) {
134             mEfid = efid;
135             mRecordNum = recordNum;
136             mOnLoaded = onLoaded;
137             mLoadAll = false;
138             mPath = path;
139         }
140 
LoadLinearFixedContext(int efid, String path, Message onLoaded)141         LoadLinearFixedContext(int efid, String path, Message onLoaded) {
142             mEfid = efid;
143             mRecordNum = 1;
144             mLoadAll = true;
145             mOnLoaded = onLoaded;
146             mPath = path;
147         }
148 
LoadLinearFixedContext(int efid, Message onLoaded)149         LoadLinearFixedContext(int efid, Message onLoaded) {
150             mEfid = efid;
151             mRecordNum = 1;
152             mLoadAll = true;
153             mOnLoaded = onLoaded;
154             mPath = null;
155         }
156     }
157 
158     /**
159      * Default constructor
160      */
IccFileHandler(UiccCardApplication app, String aid, CommandsInterface ci)161     protected IccFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) {
162         mParentApp = app;
163         mAid = aid;
164         mCi = ci;
165     }
166 
dispose()167     public void dispose() {
168     }
169 
170     //***** Public Methods
171 
172     /**
173      * Load a record from a SIM Linear Fixed EF
174      *
175      * @param fileid EF id
176      * @param path Path of the EF on the card
177      * @param recordNum 1-based (not 0-based) record number
178      * @param onLoaded
179      *
180      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
181      *
182      */
183     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
loadEFLinearFixed(int fileid, String path, int recordNum, Message onLoaded)184     public void loadEFLinearFixed(int fileid, String path, int recordNum, Message onLoaded) {
185         String efPath = (path == null) ? getEFPath(fileid) : path;
186         Message response
187                 = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
188                         new LoadLinearFixedContext(fileid, recordNum, efPath, onLoaded));
189 
190         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, efPath,
191                         0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
192     }
193 
194     /**
195      * Load a record from a SIM Linear Fixed EF
196      *
197      * @param fileid EF id
198      * @param recordNum 1-based (not 0-based) record number
199      * @param onLoaded
200      *
201      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
202      *
203      */
204     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
loadEFLinearFixed(int fileid, int recordNum, Message onLoaded)205     public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {
206         loadEFLinearFixed(fileid, getEFPath(fileid), recordNum, onLoaded);
207     }
208 
209     /**
210      * Load a image instance record from a SIM Linear Fixed EF-IMG
211      *
212      * @param recordNum 1-based (not 0-based) record number
213      * @param onLoaded
214      *
215      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
216      *
217      */
loadEFImgLinearFixed(int recordNum, Message onLoaded)218     public void loadEFImgLinearFixed(int recordNum, Message onLoaded) {
219         Message response = obtainMessage(EVENT_GET_RECORD_SIZE_IMG_DONE,
220                 new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum,
221                         onLoaded));
222 
223         mCi.iccIOForApp(COMMAND_GET_RESPONSE, IccConstants.EF_IMG,
224                     getEFPath(IccConstants.EF_IMG), recordNum,
225                     READ_RECORD_MODE_ABSOLUTE, GET_RESPONSE_EF_IMG_SIZE_BYTES,
226                     null, null, mAid, response);
227     }
228 
229     /**
230      * Get record size for a linear fixed EF
231      *
232      * @param fileid EF id
233      * @param path Path of the EF on the card
234      * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[]. recordSize[0] is
235      *                 the single record length, recordSize[1] is the total length of the EF file
236      *                 and recordSize[2] is the number of records in the EF file. So recordSize[0]
237      *                 * recordSize[2] = recordSize[1].
238      */
239     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getEFLinearRecordSize(int fileid, String path, Message onLoaded)240     public void getEFLinearRecordSize(int fileid, String path, Message onLoaded) {
241         String efPath = (path == null) ? getEFPath(fileid) : path;
242         Message response
243                 = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
244                         new LoadLinearFixedContext(fileid, efPath, onLoaded));
245         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, efPath,
246                     0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
247     }
248 
249     /**
250      * Get record size for a linear fixed EF
251      *
252      * @param fileid EF id
253      * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[]. recordSize[0] is
254      *                 the single record length, recordSize[1] is the total length of the EF file
255      *                 and recordSize[2] is the number of records in the EF file. So recordSize[0]
256      *                 * recordSize[2] = recordSize[1].
257      */
258     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getEFLinearRecordSize(int fileid, Message onLoaded)259     public void getEFLinearRecordSize(int fileid, Message onLoaded) {
260         getEFLinearRecordSize(fileid, getEFPath(fileid), onLoaded);
261     }
262 
263     /**
264      * Get record size for a transparent EF
265      *
266      * @param fileid EF id
267      * @param path Path of the EF on the card
268      * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the size of data int
269      */
getEFTransparentRecordSize(int fileid, String path, Message onLoaded)270     public void getEFTransparentRecordSize(int fileid, String path, Message onLoaded) {
271         String efPath = (path == null) ? getEFPath(fileid) : path;
272         Message response = obtainMessage(EVENT_GET_EF_TRANSPARENT_SIZE_DONE, fileid, 0, onLoaded);
273         mCi.iccIOForApp(
274                 COMMAND_GET_RESPONSE,
275                 fileid,
276                 getEFPath(fileid),
277                 0,
278                 0,
279                 GET_RESPONSE_EF_SIZE_BYTES,
280                 null,
281                 null,
282                 mAid,
283                 response);
284     }
285 
286     /**
287      * Get record size for a transparent EF
288      *
289      * @param fileid EF id
290      * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the size of the data int
291      */
getEFTransparentRecordSize(int fileid, Message onLoaded)292     public void getEFTransparentRecordSize(int fileid, Message onLoaded) {
293         getEFTransparentRecordSize(fileid, getEFPath(fileid), onLoaded);
294     }
295 
296     /**
297      * Load all records from a SIM Linear Fixed EF
298      *
299      * @param fileid EF id
300      * @param path Path of the EF on the card
301      * @param onLoaded
302      *
303      * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]>
304      */
305     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
loadEFLinearFixedAll(int fileid, String path, Message onLoaded)306     public void loadEFLinearFixedAll(int fileid, String path, Message onLoaded) {
307         String efPath = (path == null) ? getEFPath(fileid) : path;
308         Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
309                         new LoadLinearFixedContext(fileid, efPath, onLoaded));
310 
311         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, efPath,
312                         0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
313     }
314 
315     /**
316      * Load all records from a SIM Linear Fixed EF
317      *
318      * @param fileid EF id
319      * @param onLoaded
320      *
321      * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]>
322      *
323      */
324     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
loadEFLinearFixedAll(int fileid, Message onLoaded)325     public void loadEFLinearFixedAll(int fileid, Message onLoaded) {
326         loadEFLinearFixedAll(fileid, getEFPath(fileid), onLoaded);
327     }
328 
329     /**
330      * Load a SIM Transparent EF
331      *
332      * @param fileid EF id
333      * @param onLoaded
334      *
335      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
336      */
337     @UnsupportedAppUsage
loadEFTransparent(int fileid, Message onLoaded)338     public void loadEFTransparent(int fileid, Message onLoaded) {
339         Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
340                         fileid, 0, onLoaded);
341 
342         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
343                         0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
344     }
345 
346     /**
347      * Load first @size bytes from SIM Transparent EF
348      *
349      * @param fileid EF id
350      * @param size
351      * @param onLoaded
352      *
353      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
354      *
355      */
loadEFTransparent(int fileid, int size, Message onLoaded)356     public void loadEFTransparent(int fileid, int size, Message onLoaded) {
357         Message response = obtainMessage(EVENT_READ_BINARY_DONE,
358                         fileid, 0, onLoaded);
359 
360         mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
361                         0, 0, size, null, null, mAid, response);
362     }
363 
364     /**
365      * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to
366      * retrive STK's icon data.
367      *
368      * @param fileid EF id
369      * @param onLoaded
370      *
371      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
372      *
373      */
loadEFImgTransparent(int fileid, int highOffset, int lowOffset, int length, Message onLoaded)374     public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset,
375             int length, Message onLoaded) {
376         Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
377                 onLoaded);
378 
379         logd("IccFileHandler: loadEFImgTransparent fileid = " + fileid
380                 + " filePath = " + getEFPath(EF_IMG) + " highOffset = " + highOffset
381                 + " lowOffset = " + lowOffset + " length = " + length);
382 
383         /* Per TS 31.102, for displaying of Icon, under
384          * DF Telecom and DF Graphics , EF instance(s) (4FXX,transparent files)
385          * are present. The possible image file identifiers (EF instance) for
386          * EF img ( 4F20, linear fixed file) are : 4F01 ... 4F05.
387          * It should be MF_SIM + DF_TELECOM + DF_GRAPHICS, same path as EF IMG
388          */
389         mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(EF_IMG),
390                 highOffset, lowOffset, length, null, null, mAid, response);
391     }
392 
393     /**
394      * Update a record in a linear fixed EF
395      * @param fileid EF id
396      * @param path Path of the EF on the card
397      * @param recordNum 1-based (not 0-based) record number
398      * @param data must be exactly as long as the record in the EF
399      * @param pin2 for CHV2 operations, otherwist must be null
400      * @param onComplete onComplete.obj will be an AsyncResult
401      *                   onComplete.obj.userObj will be a IccIoResult on success
402      */
403     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
updateEFLinearFixed(int fileid, String path, int recordNum, byte[] data, String pin2, Message onComplete)404     public void updateEFLinearFixed(int fileid, String path, int recordNum, byte[] data,
405             String pin2, Message onComplete) {
406         String efPath = (path == null) ? getEFPath(fileid) : path;
407         mCi.iccIOForApp(COMMAND_UPDATE_RECORD, fileid, efPath,
408                         recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
409                         IccUtils.bytesToHexString(data), pin2, mAid, onComplete);
410     }
411 
412     /**
413      * Update a record in a linear fixed EF
414      * @param fileid EF id
415      * @param recordNum 1-based (not 0-based) record number
416      * @param data must be exactly as long as the record in the EF
417      * @param pin2 for CHV2 operations, otherwist must be null
418      * @param onComplete onComplete.obj will be an AsyncResult
419      *                   onComplete.obj.userObj will be a IccIoResult on success
420      */
421     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
updateEFLinearFixed(int fileid, int recordNum, byte[] data, String pin2, Message onComplete)422     public void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
423             String pin2, Message onComplete) {
424         mCi.iccIOForApp(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
425                         recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
426                         IccUtils.bytesToHexString(data), pin2, mAid, onComplete);
427     }
428 
429     /**
430      * Update a transparent EF
431      * @param fileid EF id
432      * @param data must be exactly as long as the EF
433      */
434     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
updateEFTransparent(int fileid, byte[] data, Message onComplete)435     public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
436         mCi.iccIOForApp(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
437                         0, 0, data.length,
438                         IccUtils.bytesToHexString(data), null, mAid, onComplete);
439     }
440 
441 
442     //***** Abstract Methods
443 
444 
445     //***** Private Methods
446 
sendResult(Message response, Object result, Throwable ex)447     private void sendResult(Message response, Object result, Throwable ex) {
448         if (response == null) {
449             return;
450         }
451 
452         AsyncResult.forMessage(response, result, ex);
453 
454         response.sendToTarget();
455     }
456 
processException(Message response, AsyncResult ar)457     private boolean processException(Message response, AsyncResult ar) {
458         IccException iccException;
459         boolean flag = false;
460         IccIoResult result = (IccIoResult) ar.result;
461         if (ar.exception != null) {
462             sendResult(response, null, ar.exception);
463             flag = true;
464         } else {
465             iccException = result.getException();
466             if (iccException != null) {
467                 sendResult(response, null, iccException);
468                 flag = true;
469             }
470         }
471         return flag;
472     }
473 
474     //***** Overridden from Handler
475 
476     @Override
handleMessage(Message msg)477     public void handleMessage(Message msg) {
478         AsyncResult ar;
479         IccIoResult result;
480         Message response = null;
481         String str;
482         LoadLinearFixedContext lc;
483 
484         byte data[];
485         int size;
486         int fileid;
487         int recordSize[];
488         String path = null;
489 
490         try {
491             switch (msg.what) {
492             case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE:
493                 ar = (AsyncResult)msg.obj;
494                 lc = (LoadLinearFixedContext) ar.userObj;
495                 result = (IccIoResult) ar.result;
496                 response = lc.mOnLoaded;
497 
498                 if (processException(response, (AsyncResult) msg.obj)) {
499                     break;
500                 }
501 
502                 data = result.payload;
503 
504                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
505                     EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
506                     throw new IccFileTypeMismatch();
507                 }
508 
509                 recordSize = new int[3];
510                 recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
511                 recordSize[1] = getDataFileSize(data);
512                 recordSize[2] = recordSize[1] / recordSize[0];
513 
514                 sendResult(response, recordSize, null);
515                 break;
516 
517             case EVENT_GET_RECORD_SIZE_IMG_DONE:
518             case EVENT_GET_RECORD_SIZE_DONE:
519                 ar = (AsyncResult)msg.obj;
520                 lc = (LoadLinearFixedContext) ar.userObj;
521                 result = (IccIoResult) ar.result;
522                 response = lc.mOnLoaded;
523 
524                 if (processException(response, (AsyncResult) msg.obj)) {
525                     loge("exception caught from EVENT_GET_RECORD_SIZE");
526                     break;
527                 }
528 
529                 data = result.payload;
530                 path = lc.mPath;
531 
532                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
533                     throw new IccFileTypeMismatch();
534                 }
535 
536                 if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
537                     throw new IccFileTypeMismatch();
538                 }
539 
540                 lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
541 
542                 size = getDataFileSize(data);
543 
544                 lc.mCountRecords = size / lc.mRecordSize;
545 
546                 if (lc.mLoadAll) {
547                     lc.results = new ArrayList<byte[]>(lc.mCountRecords);
548                 }
549 
550                 if (path == null) {
551                     path = getEFPath(lc.mEfid);
552                 }
553                 mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, path,
554                         lc.mRecordNum,
555                         READ_RECORD_MODE_ABSOLUTE,
556                         lc.mRecordSize, null, null, mAid,
557                         obtainMessage(EVENT_READ_RECORD_DONE, lc));
558                 break;
559             case EVENT_GET_BINARY_SIZE_DONE:
560                 ar = (AsyncResult)msg.obj;
561                 response = (Message) ar.userObj;
562                 result = (IccIoResult) ar.result;
563 
564                 if (processException(response, (AsyncResult) msg.obj)) {
565                     break;
566                 }
567 
568                 data = result.payload;
569 
570                 fileid = msg.arg1;
571 
572                 if (VDBG) {
573                     logd(String.format("Contents of the Select Response for command %x: ", fileid)
574                             + IccUtils.bytesToHexString(data));
575                 }
576 
577                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
578                     throw new IccFileTypeMismatch();
579                 }
580 
581                 if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
582                     throw new IccFileTypeMismatch();
583                 }
584 
585                 size = getDataFileSize(data);
586 
587                 mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
588                                 0, 0, size, null, null, mAid,
589                                 obtainMessage(EVENT_READ_BINARY_DONE,
590                                             fileid, 0, response));
591             break;
592 
593             case EVENT_READ_IMG_DONE:
594             case EVENT_READ_RECORD_DONE:
595 
596                 ar = (AsyncResult)msg.obj;
597                 lc = (LoadLinearFixedContext) ar.userObj;
598                 result = (IccIoResult) ar.result;
599                 response = lc.mOnLoaded;
600                 path = lc.mPath;
601 
602                 if (processException(response, (AsyncResult) msg.obj)) {
603                     break;
604                 }
605 
606                 if (!lc.mLoadAll) {
607                     sendResult(response, result.payload, null);
608                 } else {
609                     lc.results.add(result.payload);
610 
611                     lc.mRecordNum++;
612 
613                     if (lc.mRecordNum > lc.mCountRecords) {
614                         sendResult(response, lc.results, null);
615                     } else {
616                         if (path == null) {
617                             path = getEFPath(lc.mEfid);
618                         }
619 
620                         mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, path,
621                                     lc.mRecordNum,
622                                     READ_RECORD_MODE_ABSOLUTE,
623                                     lc.mRecordSize, null, null, mAid,
624                                     obtainMessage(EVENT_READ_RECORD_DONE, lc));
625                     }
626                 }
627 
628             break;
629 
630             case EVENT_READ_BINARY_DONE:
631             case EVENT_READ_ICON_DONE:
632                 ar = (AsyncResult)msg.obj;
633                 response = (Message) ar.userObj;
634                 result = (IccIoResult) ar.result;
635 
636                 if (processException(response, (AsyncResult) msg.obj)) {
637                     break;
638                 }
639 
640                 sendResult(response, result.payload, null);
641             break;
642 
643             case EVENT_GET_EF_TRANSPARENT_SIZE_DONE:
644                 ar = (AsyncResult) msg.obj;
645                 response = (Message) ar.userObj;
646                 result = (IccIoResult) ar.result;
647 
648                 if (processException(response, (AsyncResult) msg.obj)) {
649                     break;
650                 }
651 
652                 data = result.payload;
653 
654                 fileid = msg.arg1;
655 
656                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
657                     throw new IccFileTypeMismatch();
658                 }
659 
660                 if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
661                     throw new IccFileTypeMismatch();
662                 }
663 
664                 size = getDataFileSize(data);
665                 sendResult(response, size, null);
666                 break;
667 
668         }} catch (Exception exc) {
669             if (response != null) {
670                 sendResult(response, null, exc);
671             } else {
672                 loge("uncaught exception" + exc);
673             }
674         }
675     }
676 
677     /**
678      * Returns the root path of the EF file.
679      * i.e returns MainFile + DFfile as a string.
680      * Ex: For EF_ADN on a SIM, it will return "3F007F10"
681      * This function handles only EFids that are common to
682      * RUIM, SIM, USIM and other types of Icc cards.
683      *
684      * @param efid of path to retrieve
685      * @return root path of the file.
686      */
getCommonIccEFPath(int efid)687     protected String getCommonIccEFPath(int efid) {
688         switch(efid) {
689         case EF_ADN:
690         case EF_FDN:
691         case EF_MSISDN:
692         case EF_SDN:
693         case EF_EXT1:
694         case EF_EXT2:
695         case EF_EXT3:
696         case EF_PSI:
697             return MF_SIM + DF_TELECOM;
698 
699         case EF_ICCID:
700         case EF_PL:
701             return MF_SIM;
702         case EF_PBR:
703             // we only support global phonebook.
704             return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
705         case EF_IMG:
706             return MF_SIM + DF_TELECOM + DF_GRAPHICS;
707         }
708         return null;
709     }
710 
711     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getEFPath(int efid)712     protected abstract String getEFPath(int efid);
logd(String s)713     protected abstract void logd(String s);
loge(String s)714     protected abstract void loge(String s);
715 
716     /**
717      * Calculate the size of a data file
718      *
719      * @param data the raw file
720      * @return the size of the file
721      */
getDataFileSize(byte[] data)722     private static int getDataFileSize(byte[] data) {
723         return (((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
724                     + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff));
725     }
726 }
727