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