2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.internal.telephony;
20 import android.util.Log;
21 import java.util.ArrayList;
26 public abstract class IccFileHandler extends Handler implements IccConstants {
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;
36 // from TS 11.11 9.2.5
37 static protected final int READ_RECORD_MODE_ABSOLUTE = 4;
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;
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;
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;
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;
59 static protected final int RESPONSE_DATA_FILE_SIZE_1 = 2;
60 static protected final int RESPONSE_DATA_FILE_SIZE_2 = 3;
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;
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;
93 protected PhoneBase phone;
95 static class LoadLinearFixedContext {
98 int recordNum, recordSize, countRecords;
103 ArrayList<byte[]> results;
105 LoadLinearFixedContext(int efid, int recordNum, Message onLoaded) {
107 this.recordNum = recordNum;
108 this.onLoaded = onLoaded;
109 this.loadAll = false;
112 LoadLinearFixedContext(int efid, Message onLoaded) {
116 this.onLoaded = onLoaded;
121 * Default constructor
123 protected IccFileHandler(PhoneBase phone) {
128 public void dispose() {
131 //***** Public Methods
134 * Load a record from a SIM Linear Fixed EF
136 * @param fileid EF id
137 * @param recordNum 1-based (not 0-based) record number
140 * ((AsyncResult)(onLoaded.obj)).result is the byte[]
143 public void loadEFLinearFixed(int fileid, int recordNum, Message onLoaded) {
145 = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
146 new LoadLinearFixedContext(fileid, recordNum, onLoaded));
148 phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
149 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
153 * Load a image instance record from a SIM Linear Fixed EF-IMG
155 * @param recordNum 1-based (not 0-based) record number
158 * ((AsyncResult)(onLoaded.obj)).result is the byte[]
161 public void loadEFImgLinearFixed(int recordNum, Message onLoaded) {
162 Message response = obtainMessage(EVENT_READ_IMG_DONE,
163 new LoadLinearFixedContext(IccConstants.EF_IMG, recordNum,
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);
173 * get record size for a linear fixed EF
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] *
181 public void getEFLinearRecordSize(int fileid, Message onLoaded) {
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);
190 * Load all records from a SIM Linear Fixed EF
192 * @param fileid EF id
195 * ((AsyncResult)(onLoaded.obj)).result is an ArrayList<byte[]>
198 public void loadEFLinearFixedAll(int fileid, Message onLoaded) {
199 Message response = obtainMessage(EVENT_GET_RECORD_SIZE_DONE,
200 new LoadLinearFixedContext(fileid,onLoaded));
202 phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
203 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
207 * Load a SIM Transparent EF
209 * @param fileid EF id
212 * ((AsyncResult)(onLoaded.obj)).result is the byte[]
216 public void loadEFTransparent(int fileid, Message onLoaded) {
217 Message response = obtainMessage(EVENT_GET_BINARY_SIZE_DONE,
218 fileid, 0, onLoaded);
220 phone.mCM.iccIO(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
221 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, response);
225 * Load a SIM Transparent EF-IMG. Used right after loadEFImgLinearFixed to
226 * retrive STK's icon data.
228 * @param fileid EF id
231 * ((AsyncResult)(onLoaded.obj)).result is the byte[]
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,
239 phone.mCM.iccIO(COMMAND_READ_BINARY, fileid, "img", highOffset, lowOffset,
240 length, null, null, response);
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
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);
260 * Update a transparent EF
261 * @param fileid EF id
262 * @param data must be exactly as long as the EF
264 public void updateEFTransparent(int fileid, byte[] data, Message onComplete) {
265 phone.mCM.iccIO(COMMAND_UPDATE_BINARY, fileid, getEFPath(fileid),
267 IccUtils.bytesToHexString(data), null, onComplete);
271 //***** Abstract Methods
274 //***** Private Methods
276 private void sendResult(Message response, Object result, Throwable ex) {
277 if (response == null) {
281 AsyncResult.forMessage(response, result, ex);
283 response.sendToTarget();
286 //***** Overridden from Handler
288 public void handleMessage(Message msg) {
291 Message response = null;
293 LoadLinearFixedContext lc;
295 IccException iccException;
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;
310 iccException = result.getException();
311 if (iccException != null) {
312 sendResult(response, result.payload, ar.exception);
315 case EVENT_READ_ICON_DONE:
316 ar = (AsyncResult) msg.obj;
317 response = (Message) ar.userObj;
318 result = (IccIoResult) ar.result;
320 iccException = result.getException();
321 if (iccException != null) {
322 sendResult(response, result.payload, ar.exception);
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;
331 if (ar.exception != null) {
332 sendResult(response, null, ar.exception);
336 iccException = result.getException();
337 if (iccException != null) {
338 sendResult(response, null, iccException);
342 data = result.payload;
344 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
345 EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
346 throw new IccFileTypeMismatch();
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];
355 sendResult(response, recordSize, null);
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;
363 if (ar.exception != null) {
364 sendResult(response, null, ar.exception);
368 iccException = result.getException();
370 if (iccException != null) {
371 sendResult(response, null, iccException);
375 data = result.payload;
377 recordNum = lc.recordNum;
379 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
380 throw new IccFileTypeMismatch();
383 if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
384 throw new IccFileTypeMismatch();
387 lc.recordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
389 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
390 + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
392 lc.countRecords = size / lc.recordSize;
395 lc.results = new ArrayList<byte[]>(lc.countRecords);
398 phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
400 READ_RECORD_MODE_ABSOLUTE,
401 lc.recordSize, null, null,
402 obtainMessage(EVENT_READ_RECORD_DONE, lc));
404 case EVENT_GET_BINARY_SIZE_DONE:
405 ar = (AsyncResult)msg.obj;
406 response = (Message) ar.userObj;
407 result = (IccIoResult) ar.result;
409 if (ar.exception != null) {
410 sendResult(response, null, ar.exception);
414 iccException = result.getException();
416 if (iccException != null) {
417 sendResult(response, null, iccException);
421 data = result.payload;
425 if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
426 throw new IccFileTypeMismatch();
429 if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
430 throw new IccFileTypeMismatch();
433 size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
434 + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
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));
442 case EVENT_READ_RECORD_DONE:
444 ar = (AsyncResult)msg.obj;
445 lc = (LoadLinearFixedContext) ar.userObj;
446 result = (IccIoResult) ar.result;
447 response = lc.onLoaded;
449 if (ar.exception != null) {
450 sendResult(response, null, ar.exception);
454 iccException = result.getException();
456 if (iccException != null) {
457 sendResult(response, null, iccException);
462 sendResult(response, result.payload, null);
464 lc.results.add(result.payload);
468 if (lc.recordNum > lc.countRecords) {
469 sendResult(response, lc.results, null);
471 phone.mCM.iccIO(COMMAND_READ_RECORD, lc.efid, getEFPath(lc.efid),
473 READ_RECORD_MODE_ABSOLUTE,
474 lc.recordSize, null, null,
475 obtainMessage(EVENT_READ_RECORD_DONE, lc));
481 case EVENT_READ_BINARY_DONE:
482 ar = (AsyncResult)msg.obj;
483 response = (Message) ar.userObj;
484 result = (IccIoResult) ar.result;
486 if (ar.exception != null) {
487 sendResult(response, null, ar.exception);
491 iccException = result.getException();
493 if (iccException != null) {
494 sendResult(response, null, iccException);
498 sendResult(response, result.payload, null);
501 }} catch (Exception exc) {
502 if (response != null) {
503 sendResult(response, null, exc);
505 loge("uncaught exception" + exc);
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.
518 * @return root path of the file.
520 protected String getCommonIccEFPath(int efid) {
529 return MF_SIM + DF_TELECOM;
534 return MF_SIM + DF_TELECOM + DF_GRAPHICS;
539 protected abstract String getEFPath(int efid);
540 protected abstract void logd(String s);
542 protected abstract void loge(String s);