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