Home | History | Annotate | Download | only in uicc
      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.os.*;
     20 import com.android.internal.telephony.CommandsInterface;
     21 
     22 import java.util.ArrayList;
     23 
     24 /**
     25  * {@hide}
     26  */
     27 public 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 
    106         Message mOnLoaded;
    107 
    108         ArrayList<byte[]> results;
    109 
    110         LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) {
    111             mEfid = efid;
    112             mRecordNum = recordNum;
    113             mOnLoaded = onLoaded;
    114             mLoadAll = false;
    115         }
    116 
    117         LoadLinearFixedContext(int efid, Message onLoaded) {
    118             mEfid = efid;
    119             mRecordNum = 1;
    120             mLoadAll = true;
    121             mOnLoaded = onLoaded;
    122         }
    123     }
    124 
    125     /**
    126      * Default constructor
    127      */
    128     protected IccFileHandler(UiccCardApplication app, String aid, CommandsInterface ci) {
    129         mParentApp = app;
    130         mAid = aid;
    131         mCi = ci;
    132     }
    133 
    134     public void dispose() {
    135     }
    136 
    137     //***** Public Methods
    138 
    139     /**
    140      * Load a record from a SIM Linear Fixed EF
    141      *
    142      * @param fileid EF id
    143      * @param recordNum 1-based (not 0-based) record number
    144      * @param onLoaded
    145      *
    146      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
    147      *
    148      */
    149     public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {
    150         Message response
    151             = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
    152                         new LoadLinearFixedContext(fileid, recordNum, onLoaded));
    153 
    154         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
    155                         0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
    156     }
    157 
    158     /**
    159      * Load a image instance record from a SIM Linear Fixed EF-IMG
    160      *
    161      * @param recordNum 1-based (not 0-based) record number
    162      * @param onLoaded
    163      *
    164      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
    165      *
    166      */
    167     public void loadEFImgLinearFixed(int recordNum, Message onLoaded) {
    168         Message response = obtainMessage(EVENT_GET_RECORD_SIZE_IMG_DONE,
    169                 new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum,
    170                         onLoaded));
    171 
    172         mCi.iccIOForApp(COMMAND_GET_RESPONSE, IccConstants.EF_IMG,
    173                     getEFPath(IccConstants.EF_IMG), recordNum,
    174                     READ_RECORD_MODE_ABSOLUTE, GET_RESPONSE_EF_IMG_SIZE_BYTES,
    175                     null, null, mAid, response);
    176     }
    177 
    178     /**
    179      * get record size for a linear fixed EF
    180      *
    181      * @param fileid EF id
    182      * @param onLoaded ((AsnyncResult)(onLoaded.obj)).result is the recordSize[]
    183      *        int[0] is the record length int[1] is the total length of the EF
    184      *        file int[3] is the number of records in the EF file So int[0] *
    185      *        int[3] = int[1]
    186      */
    187     public void getEFLinearRecordSize(int fileid, Message onLoaded) {
    188         Message response
    189                 = obtainMessage(EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE,
    190                         new LoadLinearFixedContext(fileid, onLoaded));
    191         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
    192                     0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
    193     }
    194 
    195     /**
    196      * Load all records from a SIM Linear Fixed EF
    197      *
    198      * @param fileid EF id
    199      * @param onLoaded
    200      *
    201      * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]>
    202      *
    203      */
    204     public void loadEFLinearFixedAll(int fileid, Message onLoaded) {
    205         Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
    206                         new LoadLinearFixedContext(fileid,onLoaded));
    207 
    208         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
    209                         0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
    210     }
    211 
    212     /**
    213      * Load a SIM Transparent EF
    214      *
    215      * @param fileid EF id
    216      * @param onLoaded
    217      *
    218      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
    219      *
    220      */
    221 
    222     public void loadEFTransparent(int fileid, Message onLoaded) {
    223         Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
    224                         fileid, 0, onLoaded);
    225 
    226         mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
    227                         0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
    228     }
    229 
    230     /**
    231      * Load first @size bytes from SIM Transparent EF
    232      *
    233      * @param fileid EF id
    234      * @param size
    235      * @param onLoaded
    236      *
    237      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
    238      *
    239      */
    240     public void loadEFTransparent(int fileid, int size, Message onLoaded) {
    241         Message response = obtainMessage(EVENT_READ_BINARY_DONE,
    242                         fileid, 0, onLoaded);
    243 
    244         mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
    245                         0, 0, size, null, null, mAid, response);
    246     }
    247 
    248     /**
    249      * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to
    250      * retrive STK's icon data.
    251      *
    252      * @param fileid EF id
    253      * @param onLoaded
    254      *
    255      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
    256      *
    257      */
    258     public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset,
    259             int length, Message onLoaded) {
    260         Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
    261                 onLoaded);
    262 
    263         logd("IccFileHandler: loadEFImgTransparent fileid = " + fileid
    264                 + " filePath = " + getEFPath(EF_IMG) + " highOffset = " + highOffset
    265                 + " lowOffset = " + lowOffset + " length = " + length);
    266 
    267         /* Per TS 31.102, for displaying of Icon, under
    268          * DF Telecom and DF Graphics , EF instance(s) (4FXX,transparent files)
    269          * are present. The possible image file identifiers (EF instance) for
    270          * EF img ( 4F20, linear fixed file) are : 4F01 ... 4F05.
    271          * It should be MF_SIM + DF_TELECOM + DF_GRAPHICS, same path as EF IMG
    272          */
    273         mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(EF_IMG),
    274                 highOffset, lowOffset, length, null, null, mAid, response);
    275     }
    276 
    277     /**
    278      * Update a record in a linear fixed EF
    279      * @param fileid EF id
    280      * @param recordNum 1-based (not 0-based) record number
    281      * @param data must be exactly as long as the record in the EF
    282      * @param pin2 for CHV2 operations, otherwist must be null
    283      * @param onComplete onComplete.obj will be an AsyncResult
    284      *                   onComplete.obj.userObj will be a IccIoResult on success
    285      */
    286     public void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
    287             String pin2, Message onComplete) {
    288         mCi.iccIOForApp(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
    289                         recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
    290                         IccUtils.bytesToHexString(data), pin2, mAid, onComplete);
    291     }
    292 
    293     /**
    294      * Update a transparent EF
    295      * @param fileid EF id
    296      * @param data must be exactly as long as the EF
    297      */
    298     public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
    299         mCi.iccIOForApp(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
    300                         0, 0, data.length,
    301                         IccUtils.bytesToHexString(data), null, mAid, onComplete);
    302     }
    303 
    304 
    305     //***** Abstract Methods
    306 
    307 
    308     //***** Private Methods
    309 
    310     private void sendResult(Message response, Object result, Throwable ex) {
    311         if (response == null) {
    312             return;
    313         }
    314 
    315         AsyncResult.forMessage(response, result, ex);
    316 
    317         response.sendToTarget();
    318     }
    319 
    320     private boolean processException(Message response, AsyncResult ar) {
    321         IccException iccException;
    322         boolean flag = false;
    323         IccIoResult result = (IccIoResult) ar.result;
    324         if (ar.exception != null) {
    325             sendResult(response, null, ar.exception);
    326             flag = true;
    327         } else {
    328             iccException = result.getException();
    329             if (iccException != null) {
    330                 sendResult(response, null, iccException);
    331                 flag = true;
    332             }
    333         }
    334         return flag;
    335     }
    336 
    337     //***** Overridden from Handler
    338 
    339     @Override
    340     public void handleMessage(Message msg) {
    341         AsyncResult ar;
    342         IccIoResult result;
    343         Message response = null;
    344         String str;
    345         LoadLinearFixedContext lc;
    346 
    347         byte data[];
    348         int size;
    349         int fileid;
    350         int recordSize[];
    351 
    352         try {
    353             switch (msg.what) {
    354             case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE:
    355                 ar = (AsyncResult)msg.obj;
    356                 lc = (LoadLinearFixedContext) ar.userObj;
    357                 result = (IccIoResult) ar.result;
    358                 response = lc.mOnLoaded;
    359 
    360                 if (processException(response, (AsyncResult) msg.obj)) {
    361                     break;
    362                 }
    363 
    364                 data = result.payload;
    365 
    366                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
    367                     EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
    368                     throw new IccFileTypeMismatch();
    369                 }
    370 
    371                 recordSize = new int[3];
    372                 recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
    373                 recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
    374                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
    375                 recordSize[2] = recordSize[1] / recordSize[0];
    376 
    377                 sendResult(response, recordSize, null);
    378                 break;
    379 
    380              case EVENT_GET_RECORD_SIZE_IMG_DONE:
    381              case EVENT_GET_RECORD_SIZE_DONE:
    382                 ar = (AsyncResult)msg.obj;
    383                 lc = (LoadLinearFixedContext) ar.userObj;
    384                 result = (IccIoResult) ar.result;
    385                 response = lc.mOnLoaded;
    386 
    387                 if (processException(response, (AsyncResult) msg.obj)) {
    388                     break;
    389                 }
    390 
    391                 data = result.payload;
    392 
    393                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
    394                     throw new IccFileTypeMismatch();
    395                 }
    396 
    397                 if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
    398                     throw new IccFileTypeMismatch();
    399                 }
    400 
    401                 lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
    402 
    403                 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
    404                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
    405 
    406                 lc.mCountRecords = size / lc.mRecordSize;
    407 
    408                  if (lc.mLoadAll) {
    409                      lc.results = new ArrayList<byte[]>(lc.mCountRecords);
    410                  }
    411 
    412                  mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, getEFPath(lc.mEfid),
    413                          lc.mRecordNum,
    414                          READ_RECORD_MODE_ABSOLUTE,
    415                          lc.mRecordSize, null, null, mAid,
    416                          obtainMessage(EVENT_READ_RECORD_DONE, lc));
    417                  break;
    418             case EVENT_GET_BINARY_SIZE_DONE:
    419                 ar = (AsyncResult)msg.obj;
    420                 response = (Message) ar.userObj;
    421                 result = (IccIoResult) ar.result;
    422 
    423                 if (processException(response, (AsyncResult) msg.obj)) {
    424                     break;
    425                 }
    426 
    427                 data = result.payload;
    428 
    429                 fileid = msg.arg1;
    430 
    431                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
    432                     throw new IccFileTypeMismatch();
    433                 }
    434 
    435                 if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
    436                     throw new IccFileTypeMismatch();
    437                 }
    438 
    439                 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
    440                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
    441 
    442                 mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
    443                                 0, 0, size, null, null, mAid,
    444                                 obtainMessage(EVENT_READ_BINARY_DONE,
    445                                               fileid, 0, response));
    446             break;
    447 
    448             case EVENT_READ_IMG_DONE:
    449             case EVENT_READ_RECORD_DONE:
    450 
    451                 ar = (AsyncResult)msg.obj;
    452                 lc = (LoadLinearFixedContext) ar.userObj;
    453                 result = (IccIoResult) ar.result;
    454                 response = lc.mOnLoaded;
    455 
    456                 if (processException(response, (AsyncResult) msg.obj)) {
    457                     break;
    458                 }
    459 
    460                 if (!lc.mLoadAll) {
    461                     sendResult(response, result.payload, null);
    462                 } else {
    463                     lc.results.add(result.payload);
    464 
    465                     lc.mRecordNum++;
    466 
    467                     if (lc.mRecordNum > lc.mCountRecords) {
    468                         sendResult(response, lc.results, null);
    469                     } else {
    470                         mCi.iccIOForApp(COMMAND_READ_RECORD, lc.mEfid, getEFPath(lc.mEfid),
    471                                     lc.mRecordNum,
    472                                     READ_RECORD_MODE_ABSOLUTE,
    473                                     lc.mRecordSize, null, null, mAid,
    474                                     obtainMessage(EVENT_READ_RECORD_DONE, lc));
    475                     }
    476                 }
    477 
    478             break;
    479 
    480             case EVENT_READ_BINARY_DONE:
    481             case EVENT_READ_ICON_DONE:
    482                 ar = (AsyncResult)msg.obj;
    483                 response = (Message) ar.userObj;
    484                 result = (IccIoResult) ar.result;
    485 
    486                 if (processException(response, (AsyncResult) msg.obj)) {
    487                     break;
    488                 }
    489 
    490                 sendResult(response, result.payload, null);
    491             break;
    492 
    493         }} catch (Exception exc) {
    494             if (response != null) {
    495                 sendResult(response, null, exc);
    496             } else {
    497                 loge("uncaught exception" + exc);
    498             }
    499         }
    500     }
    501 
    502     /**
    503      * Returns the root path of the EF file.
    504      * i.e returns MasterFile + DFfile as a string.
    505      * Ex: For EF_ADN on a SIM, it will return "3F007F10"
    506      * This function handles only EFids that are common to
    507      * RUIM, SIM, USIM and other types of Icc cards.
    508      *
    509      * @param efid of path to retrieve
    510      * @return root path of the file.
    511      */
    512     protected String getCommonIccEFPath(int efid) {
    513         switch(efid) {
    514         case EF_ADN:
    515         case EF_FDN:
    516         case EF_MSISDN:
    517         case EF_SDN:
    518         case EF_EXT1:
    519         case EF_EXT2:
    520         case EF_EXT3:
    521         case EF_PSI:
    522             return MF_SIM + DF_TELECOM;
    523 
    524         case EF_ICCID:
    525         case EF_PL:
    526             return MF_SIM;
    527         case EF_PBR:
    528             // we only support global phonebook.
    529             return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
    530         case EF_IMG:
    531             return MF_SIM + DF_TELECOM + DF_GRAPHICS;
    532         }
    533         return null;
    534     }
    535 
    536     protected abstract String getEFPath(int efid);
    537     protected abstract void logd(String s);
    538 
    539     protected abstract void loge(String s);
    540 
    541 }
    542