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