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