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