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