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