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