• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
LoadLinearFixedContext(int efid, int recordNum, Message onLoaded)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 
LoadLinearFixedContext(int efid, Message onLoaded)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      */
IccFileHandler(PhoneBase phone)123     protected IccFileHandler(PhoneBase phone) {
124         super();
125         this.phone = phone;
126     }
127 
dispose()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      */
loadEFLinearFixed(int fileid, int recordNum, Message onLoaded)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      */
loadEFImgLinearFixed(int recordNum, Message onLoaded)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      */
getEFLinearRecordSize(int fileid, Message onLoaded)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      */
loadEFLinearFixedAll(int fileid, Message onLoaded)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 
loadEFTransparent(int fileid, Message onLoaded)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      */
loadEFImgTransparent(int fileid, int highOffset, int lowOffset, int length, Message onLoaded)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      */
updateEFLinearFixed(int fileid, int recordNum, byte[] data, String pin2, Message onComplete)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      */
updateEFTransparent(int fileid, byte[] data, Message onComplete)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 
sendResult(Message response, Object result, Throwable ex)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 
handleMessage(Message msg)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      */
getCommonIccEFPath(int efid)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             return MF_SIM;
533         case EF_IMG:
534             return MF_SIM + DF_TELECOM + DF_GRAPHICS;
535         }
536         return null;
537     }
538 
getEFPath(int efid)539     protected abstract String getEFPath(int efid);
logd(String s)540     protected abstract void logd(String s);
541 
loge(String s)542     protected abstract void loge(String s);
543 
544 }
545