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 final CommandsInterface mCi;
     94     protected final UiccCardApplication mParentApp;
     95     protected final 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(UiccCardApplication app, String aid, CommandsInterface ci) {
    126         mParentApp = app;
    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 first @size bytes from SIM Transparent EF
    229      *
    230      * @param fileid EF id
    231      * @param size
    232      * @param onLoaded
    233      *
    234      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
    235      *
    236      */
    237     public void loadEFTransparent(int fileid, int size, Message onLoaded) {
    238         Message response = obtainMessage(EVENT_READ_BINARY_DONE,
    239                         fileid, 0, onLoaded);
    240 
    241         mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
    242                         0, 0, size, null, null, mAid, response);
    243     }
    244 
    245     /**
    246      * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to
    247      * retrive STK's icon data.
    248      *
    249      * @param fileid EF id
    250      * @param onLoaded
    251      *
    252      * ((AsyncResult)(onLoaded.obj)).result is the byte[]
    253      *
    254      */
    255     public void loadEFImgTransparent(int fileid, int highOffset, int lowOffset,
    256             int length, Message onLoaded) {
    257         Message response = obtainMessage(EVENT_READ_ICON_DONE, fileid, 0,
    258                 onLoaded);
    259 
    260         mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
    261                 length, null, null, mAid, response);
    262     }
    263 
    264     /**
    265      * Update a record in a linear fixed EF
    266      * @param fileid EF id
    267      * @param recordNum 1-based (not 0-based) record number
    268      * @param data must be exactly as long as the record in the EF
    269      * @param pin2 for CHV2 operations, otherwist must be null
    270      * @param onComplete onComplete.obj will be an AsyncResult
    271      *                   onComplete.obj.userObj will be a IccIoResult on success
    272      */
    273     public void updateEFLinearFixed(int fileid, int recordNum, byte[] data,
    274             String pin2, Message onComplete) {
    275         mCi.iccIOForApp(COMMAND_UPDATE_RECORD, fileid, getEFPath(fileid),
    276                         recordNum, READ_RECORD_MODE_ABSOLUTE, data.length,
    277                         IccUtils.bytesToHexString(data), pin2, mAid, onComplete);
    278     }
    279 
    280     /**
    281      * Update a transparent EF
    282      * @param fileid EF id
    283      * @param data must be exactly as long as the EF
    284      */
    285     public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
    286         mCi.iccIOForApp(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
    287                         0, 0, data.length,
    288                         IccUtils.bytesToHexString(data), null, mAid, onComplete);
    289     }
    290 
    291 
    292     //***** Abstract Methods
    293 
    294 
    295     //***** Private Methods
    296 
    297     private void sendResult(Message response, Object result, Throwable ex) {
    298         if (response == null) {
    299             return;
    300         }
    301 
    302         AsyncResult.forMessage(response, result, ex);
    303 
    304         response.sendToTarget();
    305     }
    306 
    307     //***** Overridden from Handler
    308 
    309     public void handleMessage(Message msg) {
    310         AsyncResult ar;
    311         IccIoResult result;
    312         Message response = null;
    313         String str;
    314         LoadLinearFixedContext lc;
    315 
    316         IccException iccException;
    317         byte data[];
    318         int size;
    319         int fileid;
    320         int recordNum;
    321         int recordSize[];
    322 
    323         try {
    324             switch (msg.what) {
    325             case EVENT_READ_IMG_DONE:
    326                 ar = (AsyncResult) msg.obj;
    327                 lc = (LoadLinearFixedContext) ar.userObj;
    328                 result = (IccIoResult) ar.result;
    329                 response = lc.onLoaded;
    330 
    331                 iccException = result.getException();
    332                 if (iccException != null) {
    333                     sendResult(response, result.payload, ar.exception);
    334                 }
    335                 break;
    336             case EVENT_READ_ICON_DONE:
    337                 ar = (AsyncResult) msg.obj;
    338                 response = (Message) ar.userObj;
    339                 result = (IccIoResult) ar.result;
    340 
    341                 iccException = result.getException();
    342                 if (iccException != null) {
    343                     sendResult(response, result.payload, ar.exception);
    344                 }
    345                 break;
    346             case EVENT_GET_EF_LINEAR_RECORD_SIZE_DONE:
    347                 ar = (AsyncResult)msg.obj;
    348                 lc = (LoadLinearFixedContext) ar.userObj;
    349                 result = (IccIoResult) ar.result;
    350                 response = lc.onLoaded;
    351 
    352                 if (ar.exception != null) {
    353                     sendResult(response, null, ar.exception);
    354                     break;
    355                 }
    356 
    357                 iccException = result.getException();
    358                 if (iccException != null) {
    359                     sendResult(response, null, iccException);
    360                     break;
    361                 }
    362 
    363                 data = result.payload;
    364 
    365                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
    366                     EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
    367                     throw new IccFileTypeMismatch();
    368                 }
    369 
    370                 recordSize = new int[3];
    371                 recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
    372                 recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
    373                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
    374                 recordSize[2] = recordSize[1] / recordSize[0];
    375 
    376                 sendResult(response, recordSize, null);
    377                 break;
    378              case EVENT_GET_RECORD_SIZE_DONE:
    379                 ar = (AsyncResult)msg.obj;
    380                 lc = (LoadLinearFixedContext) ar.userObj;
    381                 result = (IccIoResult) ar.result;
    382                 response = lc.onLoaded;
    383 
    384                 if (ar.exception != null) {
    385                     sendResult(response, null, ar.exception);
    386                     break;
    387                 }
    388 
    389                 iccException = result.getException();
    390 
    391                 if (iccException != null) {
    392                     sendResult(response, null, iccException);
    393                     break;
    394                 }
    395 
    396                 data = result.payload;
    397                 fileid = lc.efid;
    398                 recordNum = lc.recordNum;
    399 
    400                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
    401                     throw new IccFileTypeMismatch();
    402                 }
    403 
    404                 if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
    405                     throw new IccFileTypeMismatch();
    406                 }
    407 
    408                 lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
    409 
    410                 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
    411                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
    412 
    413                 lc.countRecords = size / lc.recordSize;
    414 
    415                  if (lc.loadAll) {
    416                      lc.results = new ArrayList<byte[]>(lc.countRecords);
    417                  }
    418 
    419                  mCi.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
    420                          lc.recordNum,
    421                          READ_RECORD_MODE_ABSOLUTE,
    422                          lc.recordSize, null, null, mAid,
    423                          obtainMessage(EVENT_READ_RECORD_DONE, lc));
    424                  break;
    425             case EVENT_GET_BINARY_SIZE_DONE:
    426                 ar = (AsyncResult)msg.obj;
    427                 response = (Message) ar.userObj;
    428                 result = (IccIoResult) ar.result;
    429 
    430                 if (ar.exception != null) {
    431                     sendResult(response, null, ar.exception);
    432                     break;
    433                 }
    434 
    435                 iccException = result.getException();
    436 
    437                 if (iccException != null) {
    438                     sendResult(response, null, iccException);
    439                     break;
    440                 }
    441 
    442                 data = result.payload;
    443 
    444                 fileid = msg.arg1;
    445 
    446                 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
    447                     throw new IccFileTypeMismatch();
    448                 }
    449 
    450                 if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
    451                     throw new IccFileTypeMismatch();
    452                 }
    453 
    454                 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
    455                        + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
    456 
    457                 mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
    458                                 0, 0, size, null, null, mAid,
    459                                 obtainMessage(EVENT_READ_BINARY_DONE,
    460                                               fileid, 0, response));
    461             break;
    462 
    463             case EVENT_READ_RECORD_DONE:
    464 
    465                 ar = (AsyncResult)msg.obj;
    466                 lc = (LoadLinearFixedContext) ar.userObj;
    467                 result = (IccIoResult) ar.result;
    468                 response = lc.onLoaded;
    469 
    470                 if (ar.exception != null) {
    471                     sendResult(response, null, ar.exception);
    472                     break;
    473                 }
    474 
    475                 iccException = result.getException();
    476 
    477                 if (iccException != null) {
    478                     sendResult(response, null, iccException);
    479                     break;
    480                 }
    481 
    482                 if (!lc.loadAll) {
    483                     sendResult(response, result.payload, null);
    484                 } else {
    485                     lc.results.add(result.payload);
    486 
    487                     lc.recordNum++;
    488 
    489                     if (lc.recordNum > lc.countRecords) {
    490                         sendResult(response, lc.results, null);
    491                     } else {
    492                         mCi.iccIOForApp(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
    493                                     lc.recordNum,
    494                                     READ_RECORD_MODE_ABSOLUTE,
    495                                     lc.recordSize, null, null, mAid,
    496                                     obtainMessage(EVENT_READ_RECORD_DONE, lc));
    497                     }
    498                 }
    499 
    500             break;
    501 
    502             case EVENT_READ_BINARY_DONE:
    503                 ar = (AsyncResult)msg.obj;
    504                 response = (Message) ar.userObj;
    505                 result = (IccIoResult) ar.result;
    506 
    507                 if (ar.exception != null) {
    508                     sendResult(response, null, ar.exception);
    509                     break;
    510                 }
    511 
    512                 iccException = result.getException();
    513 
    514                 if (iccException != null) {
    515                     sendResult(response, null, iccException);
    516                     break;
    517                 }
    518 
    519                 sendResult(response, result.payload, null);
    520             break;
    521 
    522         }} catch (Exception exc) {
    523             if (response != null) {
    524                 sendResult(response, null, exc);
    525             } else {
    526                 loge("uncaught exception" + exc);
    527             }
    528         }
    529     }
    530 
    531     /**
    532      * Returns the root path of the EF file.
    533      * i.e returns MasterFile + DFfile as a string.
    534      * Ex: For EF_ADN on a SIM, it will return "3F007F10"
    535      * This function handles only EFids that are common to
    536      * RUIM, SIM, USIM and other types of Icc cards.
    537      *
    538      * @param efId
    539      * @return root path of the file.
    540      */
    541     protected String getCommonIccEFPath(int efid) {
    542         switch(efid) {
    543         case EF_ADN:
    544         case EF_FDN:
    545         case EF_MSISDN:
    546         case EF_SDN:
    547         case EF_EXT1:
    548         case EF_EXT2:
    549         case EF_EXT3:
    550             return MF_SIM + DF_TELECOM;
    551 
    552         case EF_ICCID:
    553         case EF_PL:
    554             return MF_SIM;
    555         case EF_PBR:
    556             // we only support global phonebook.
    557             return MF_SIM + DF_TELECOM + DF_PHONEBOOK;
    558         case EF_IMG:
    559             return MF_SIM + DF_TELECOM + DF_GRAPHICS;
    560         }
    561         return null;
    562     }
    563 
    564     protected abstract String getEFPath(int efid);
    565     protected abstract void logd(String s);
    566 
    567     protected abstract void loge(String s);
    568 
    569 }
    570