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