OSDN Git Service

Merge "cherrypick from master: Change-Id: I169749dc594ca1d79a802db4c53ec330924fdd2c...
[android-x86/frameworks-base.git] / telephony / java / com / android / internal / telephony / IccFileHandler.java
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             return MF_SIM;
533         case EF_IMG:
534             return MF_SIM + DF_TELECOM + DF_GRAPHICS;
535         }
536         return null;
537     }
538
539     protected abstract String getEFPath(int efid);
540     protected abstract void logd(String s);
541
542     protected abstract void loge(String s);
543
544 }