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