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 return MF_SIM + DF_TELECOM; 522 523 case EF_ICCID: 524 case EF_PL: 525 return MF_SIM; 526 case EF_PBR: 527 // we only support global phonebook. 528 return MF_SIM + DF_TELECOM + DF_PHONEBOOK; 529 case EF_IMG: 530 return MF_SIM + DF_TELECOM + DF_GRAPHICS; 531 } 532 return null; 533 } 534 535 protected abstract String getEFPath(int efid); 536 protected abstract void logd(String s); 537 538 protected abstract void loge(String s); 539 540 } 541