AdnRecordLoader.java revision d720945f2be5ea5fe0faf67e67d9ea0e184eba67
1/* 2 * Copyright (C) 2006 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 17package com.android.internal.telephony.uicc; 18 19import java.util.ArrayList; 20 21import android.os.AsyncResult; 22import android.os.Handler; 23import android.os.Looper; 24import android.os.Message; 25import android.telephony.Rlog; 26 27public class AdnRecordLoader extends Handler { 28 final static String LOG_TAG = "RIL_AdnRecordLoader"; 29 30 //***** Instance Variables 31 32 private IccFileHandler mFh; 33 int ef; 34 int extensionEF; 35 int pendingExtLoads; 36 Message userResponse; 37 String pin2; 38 39 // For "load one" 40 int recordNumber; 41 42 // for "load all" 43 ArrayList<AdnRecord> adns; // only valid after EVENT_ADN_LOAD_ALL_DONE 44 45 // Either an AdnRecord or a reference to adns depending 46 // if this is a load one or load all operation 47 Object result; 48 49 //***** Event Constants 50 51 static final int EVENT_ADN_LOAD_DONE = 1; 52 static final int EVENT_EXT_RECORD_LOAD_DONE = 2; 53 static final int EVENT_ADN_LOAD_ALL_DONE = 3; 54 static final int EVENT_EF_LINEAR_RECORD_SIZE_DONE = 4; 55 static final int EVENT_UPDATE_RECORD_DONE = 5; 56 57 //***** Constructor 58 59 AdnRecordLoader(IccFileHandler fh) { 60 // The telephony unit-test cases may create AdnRecords 61 // in secondary threads 62 super(Looper.getMainLooper()); 63 mFh = fh; 64 } 65 66 /** 67 * Resulting AdnRecord is placed in response.obj.result 68 * or response.obj.exception is set 69 */ 70 public void 71 loadFromEF(int ef, int extensionEF, int recordNumber, 72 Message response) { 73 this.ef = ef; 74 this.extensionEF = extensionEF; 75 this.recordNumber = recordNumber; 76 this.userResponse = response; 77 78 mFh.loadEFLinearFixed( 79 ef, recordNumber, 80 obtainMessage(EVENT_ADN_LOAD_DONE)); 81 82 } 83 84 85 /** 86 * Resulting ArrayList<adnRecord> is placed in response.obj.result 87 * or response.obj.exception is set 88 */ 89 public void 90 loadAllFromEF(int ef, int extensionEF, 91 Message response) { 92 this.ef = ef; 93 this.extensionEF = extensionEF; 94 this.userResponse = response; 95 96 mFh.loadEFLinearFixedAll( 97 ef, 98 obtainMessage(EVENT_ADN_LOAD_ALL_DONE)); 99 100 } 101 102 /** 103 * Write adn to a EF SIM record 104 * It will get the record size of EF record and compose hex adn array 105 * then write the hex array to EF record 106 * 107 * @param adn is set with alphaTag and phone number 108 * @param ef EF fileid 109 * @param extensionEF extension EF fileid 110 * @param recordNumber 1-based record index 111 * @param pin2 for CHV2 operations, must be null if pin2 is not needed 112 * @param response will be sent to its handler when completed 113 */ 114 public void 115 updateEF(AdnRecord adn, int ef, int extensionEF, int recordNumber, 116 String pin2, Message response) { 117 this.ef = ef; 118 this.extensionEF = extensionEF; 119 this.recordNumber = recordNumber; 120 this.userResponse = response; 121 this.pin2 = pin2; 122 123 mFh.getEFLinearRecordSize( ef, 124 obtainMessage(EVENT_EF_LINEAR_RECORD_SIZE_DONE, adn)); 125 } 126 127 //***** Overridden from Handler 128 129 public void 130 handleMessage(Message msg) { 131 AsyncResult ar; 132 byte data[]; 133 AdnRecord adn; 134 135 try { 136 switch (msg.what) { 137 case EVENT_EF_LINEAR_RECORD_SIZE_DONE: 138 ar = (AsyncResult)(msg.obj); 139 adn = (AdnRecord)(ar.userObj); 140 141 if (ar.exception != null) { 142 throw new RuntimeException("get EF record size failed", 143 ar.exception); 144 } 145 146 int[] recordSize = (int[])ar.result; 147 // recordSize is int[3] array 148 // int[0] is the record length 149 // int[1] is the total length of the EF file 150 // int[2] is the number of records in the EF file 151 // So int[0] * int[2] = int[1] 152 if (recordSize.length != 3 || recordNumber > recordSize[2]) { 153 throw new RuntimeException("get wrong EF record size format", 154 ar.exception); 155 } 156 157 data = adn.buildAdnString(recordSize[0]); 158 159 if(data == null) { 160 throw new RuntimeException("wrong ADN format", 161 ar.exception); 162 } 163 164 mFh.updateEFLinearFixed(ef, recordNumber, 165 data, pin2, obtainMessage(EVENT_UPDATE_RECORD_DONE)); 166 167 pendingExtLoads = 1; 168 169 break; 170 case EVENT_UPDATE_RECORD_DONE: 171 ar = (AsyncResult)(msg.obj); 172 if (ar.exception != null) { 173 throw new RuntimeException("update EF adn record failed", 174 ar.exception); 175 } 176 pendingExtLoads = 0; 177 result = null; 178 break; 179 case EVENT_ADN_LOAD_DONE: 180 ar = (AsyncResult)(msg.obj); 181 data = (byte[])(ar.result); 182 183 if (ar.exception != null) { 184 throw new RuntimeException("load failed", ar.exception); 185 } 186 187 if (false) { 188 Rlog.d(LOG_TAG,"ADN EF: 0x" 189 + Integer.toHexString(ef) 190 + ":" + recordNumber 191 + "\n" + IccUtils.bytesToHexString(data)); 192 } 193 194 adn = new AdnRecord(ef, recordNumber, data); 195 result = adn; 196 197 if (adn.hasExtendedRecord()) { 198 // If we have a valid value in the ext record field, 199 // we're not done yet: we need to read the corresponding 200 // ext record and append it 201 202 pendingExtLoads = 1; 203 204 mFh.loadEFLinearFixed( 205 extensionEF, adn.extRecord, 206 obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); 207 } 208 break; 209 210 case EVENT_EXT_RECORD_LOAD_DONE: 211 ar = (AsyncResult)(msg.obj); 212 data = (byte[])(ar.result); 213 adn = (AdnRecord)(ar.userObj); 214 215 if (ar.exception != null) { 216 throw new RuntimeException("load failed", ar.exception); 217 } 218 219 Rlog.d(LOG_TAG,"ADN extension EF: 0x" 220 + Integer.toHexString(extensionEF) 221 + ":" + adn.extRecord 222 + "\n" + IccUtils.bytesToHexString(data)); 223 224 adn.appendExtRecord(data); 225 226 pendingExtLoads--; 227 // result should have been set in 228 // EVENT_ADN_LOAD_DONE or EVENT_ADN_LOAD_ALL_DONE 229 break; 230 231 case EVENT_ADN_LOAD_ALL_DONE: 232 ar = (AsyncResult)(msg.obj); 233 ArrayList<byte[]> datas = (ArrayList<byte[]>)(ar.result); 234 235 if (ar.exception != null) { 236 throw new RuntimeException("load failed", ar.exception); 237 } 238 239 adns = new ArrayList<AdnRecord>(datas.size()); 240 result = adns; 241 pendingExtLoads = 0; 242 243 for(int i = 0, s = datas.size() ; i < s ; i++) { 244 adn = new AdnRecord(ef, 1 + i, datas.get(i)); 245 adns.add(adn); 246 247 if (adn.hasExtendedRecord()) { 248 // If we have a valid value in the ext record field, 249 // we're not done yet: we need to read the corresponding 250 // ext record and append it 251 252 pendingExtLoads++; 253 254 mFh.loadEFLinearFixed( 255 extensionEF, adn.extRecord, 256 obtainMessage(EVENT_EXT_RECORD_LOAD_DONE, adn)); 257 } 258 } 259 break; 260 } 261 } catch (RuntimeException exc) { 262 if (userResponse != null) { 263 AsyncResult.forMessage(userResponse) 264 .exception = exc; 265 userResponse.sendToTarget(); 266 // Loading is all or nothing--either every load succeeds 267 // or we fail the whole thing. 268 userResponse = null; 269 } 270 return; 271 } 272 273 if (userResponse != null && pendingExtLoads == 0) { 274 AsyncResult.forMessage(userResponse).result 275 = result; 276 277 userResponse.sendToTarget(); 278 userResponse = null; 279 } 280 } 281 282 283} 284