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