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