PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/android/upstream/com/android/internal/telephony/gsm/UsimPhoneBookManager.java

https://bitbucket.org/festevezga/xobotos
Java | 452 lines | 355 code | 50 blank | 47 comment | 63 complexity | ae83840d407f3082d7a792ea2502675f MD5 | raw file
  1. /*
  2. * Copyright (C) 2009 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. package com.android.internal.telephony.gsm;
  17. import android.os.AsyncResult;
  18. import android.os.Handler;
  19. import android.os.Message;
  20. import android.util.Log;
  21. import com.android.internal.telephony.AdnRecord;
  22. import com.android.internal.telephony.AdnRecordCache;
  23. import com.android.internal.telephony.IccConstants;
  24. import com.android.internal.telephony.IccUtils;
  25. import com.android.internal.telephony.PhoneBase;
  26. import java.util.ArrayList;
  27. import java.util.HashMap;
  28. import java.util.Map;
  29. /**
  30. * This class implements reading and parsing USIM records.
  31. * Refer to Spec 3GPP TS 31.102 for more details.
  32. *
  33. * {@hide}
  34. */
  35. public class UsimPhoneBookManager extends Handler implements IccConstants {
  36. private static final String LOG_TAG = "GSM";
  37. private static final boolean DBG = true;
  38. private PbrFile mPbrFile;
  39. private Boolean mIsPbrPresent;
  40. private PhoneBase mPhone;
  41. private AdnRecordCache mAdnCache;
  42. private Object mLock = new Object();
  43. private ArrayList<AdnRecord> mPhoneBookRecords;
  44. private boolean mEmailPresentInIap = false;
  45. private int mEmailTagNumberInIap = 0;
  46. private ArrayList<byte[]> mIapFileRecord;
  47. private ArrayList<byte[]> mEmailFileRecord;
  48. private Map<Integer, ArrayList<String>> mEmailsForAdnRec;
  49. private boolean mRefreshCache = false;
  50. private static final int EVENT_PBR_LOAD_DONE = 1;
  51. private static final int EVENT_USIM_ADN_LOAD_DONE = 2;
  52. private static final int EVENT_IAP_LOAD_DONE = 3;
  53. private static final int EVENT_EMAIL_LOAD_DONE = 4;
  54. private static final int USIM_TYPE1_TAG = 0xA8;
  55. private static final int USIM_TYPE2_TAG = 0xA9;
  56. private static final int USIM_TYPE3_TAG = 0xAA;
  57. private static final int USIM_EFADN_TAG = 0xC0;
  58. private static final int USIM_EFIAP_TAG = 0xC1;
  59. private static final int USIM_EFEXT1_TAG = 0xC2;
  60. private static final int USIM_EFSNE_TAG = 0xC3;
  61. private static final int USIM_EFANR_TAG = 0xC4;
  62. private static final int USIM_EFPBC_TAG = 0xC5;
  63. private static final int USIM_EFGRP_TAG = 0xC6;
  64. private static final int USIM_EFAAS_TAG = 0xC7;
  65. private static final int USIM_EFGSD_TAG = 0xC8;
  66. private static final int USIM_EFUID_TAG = 0xC9;
  67. private static final int USIM_EFEMAIL_TAG = 0xCA;
  68. private static final int USIM_EFCCP1_TAG = 0xCB;
  69. public UsimPhoneBookManager(PhoneBase phone, AdnRecordCache cache) {
  70. mPhone = phone;
  71. mPhoneBookRecords = new ArrayList<AdnRecord>();
  72. mPbrFile = null;
  73. // We assume its present, after the first read this is updated.
  74. // So we don't have to read from UICC if its not present on subsequent reads.
  75. mIsPbrPresent = true;
  76. mAdnCache = cache;
  77. }
  78. public void reset() {
  79. mPhoneBookRecords.clear();
  80. mIapFileRecord = null;
  81. mEmailFileRecord = null;
  82. mPbrFile = null;
  83. mIsPbrPresent = true;
  84. mRefreshCache = false;
  85. }
  86. public ArrayList<AdnRecord> loadEfFilesFromUsim() {
  87. synchronized (mLock) {
  88. if (!mPhoneBookRecords.isEmpty()) {
  89. if (mRefreshCache) {
  90. mRefreshCache = false;
  91. refreshCache();
  92. }
  93. return mPhoneBookRecords;
  94. }
  95. if (!mIsPbrPresent) return null;
  96. // Check if the PBR file is present in the cache, if not read it
  97. // from the USIM.
  98. if (mPbrFile == null) {
  99. readPbrFileAndWait();
  100. }
  101. if (mPbrFile == null) return null;
  102. int numRecs = mPbrFile.mFileIds.size();
  103. for (int i = 0; i < numRecs; i++) {
  104. readAdnFileAndWait(i);
  105. readEmailFileAndWait(i);
  106. }
  107. // All EF files are loaded, post the response.
  108. }
  109. return mPhoneBookRecords;
  110. }
  111. private void refreshCache() {
  112. if (mPbrFile == null) return;
  113. mPhoneBookRecords.clear();
  114. int numRecs = mPbrFile.mFileIds.size();
  115. for (int i = 0; i < numRecs; i++) {
  116. readAdnFileAndWait(i);
  117. }
  118. }
  119. public void invalidateCache() {
  120. mRefreshCache = true;
  121. }
  122. private void readPbrFileAndWait() {
  123. mPhone.getIccFileHandler().loadEFLinearFixedAll(EF_PBR, obtainMessage(EVENT_PBR_LOAD_DONE));
  124. try {
  125. mLock.wait();
  126. } catch (InterruptedException e) {
  127. Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
  128. }
  129. }
  130. private void readEmailFileAndWait(int recNum) {
  131. Map <Integer,Integer> fileIds;
  132. fileIds = mPbrFile.mFileIds.get(recNum);
  133. if (fileIds == null) return;
  134. if (fileIds.containsKey(USIM_EFEMAIL_TAG)) {
  135. int efid = fileIds.get(USIM_EFEMAIL_TAG);
  136. // Check if the EFEmail is a Type 1 file or a type 2 file.
  137. // If mEmailPresentInIap is true, its a type 2 file.
  138. // So we read the IAP file and then read the email records.
  139. // instead of reading directly.
  140. if (mEmailPresentInIap) {
  141. readIapFileAndWait(fileIds.get(USIM_EFIAP_TAG));
  142. if (mIapFileRecord == null) {
  143. Log.e(LOG_TAG, "Error: IAP file is empty");
  144. return;
  145. }
  146. }
  147. // Read the EFEmail file.
  148. mPhone.getIccFileHandler().loadEFLinearFixedAll(fileIds.get(USIM_EFEMAIL_TAG),
  149. obtainMessage(EVENT_EMAIL_LOAD_DONE));
  150. try {
  151. mLock.wait();
  152. } catch (InterruptedException e) {
  153. Log.e(LOG_TAG, "Interrupted Exception in readEmailFileAndWait");
  154. }
  155. if (mEmailFileRecord == null) {
  156. Log.e(LOG_TAG, "Error: Email file is empty");
  157. return;
  158. }
  159. updatePhoneAdnRecord();
  160. }
  161. }
  162. private void readIapFileAndWait(int efid) {
  163. mPhone.getIccFileHandler().loadEFLinearFixedAll(efid, obtainMessage(EVENT_IAP_LOAD_DONE));
  164. try {
  165. mLock.wait();
  166. } catch (InterruptedException e) {
  167. Log.e(LOG_TAG, "Interrupted Exception in readIapFileAndWait");
  168. }
  169. }
  170. private void updatePhoneAdnRecord() {
  171. if (mEmailFileRecord == null) return;
  172. int numAdnRecs = mPhoneBookRecords.size();
  173. if (mIapFileRecord != null) {
  174. // The number of records in the IAP file is same as the number of records in ADN file.
  175. // The order of the pointers in an EFIAP shall be the same as the order of file IDs
  176. // that appear in the TLV object indicated by Tag 'A9' in the reference file record.
  177. // i.e value of mEmailTagNumberInIap
  178. for (int i = 0; i < numAdnRecs; i++) {
  179. byte[] record = null;
  180. try {
  181. record = mIapFileRecord.get(i);
  182. } catch (IndexOutOfBoundsException e) {
  183. Log.e(LOG_TAG, "Error: Improper ICC card: No IAP record for ADN, continuing");
  184. break;
  185. }
  186. int recNum = record[mEmailTagNumberInIap];
  187. if (recNum != -1) {
  188. String[] emails = new String[1];
  189. // SIM record numbers are 1 based
  190. emails[0] = readEmailRecord(recNum - 1);
  191. AdnRecord rec = mPhoneBookRecords.get(i);
  192. if (rec != null) {
  193. rec.setEmails(emails);
  194. } else {
  195. // might be a record with only email
  196. rec = new AdnRecord("", "", emails);
  197. }
  198. mPhoneBookRecords.set(i, rec);
  199. }
  200. }
  201. }
  202. // ICC cards can be made such that they have an IAP file but all
  203. // records are empty. So we read both type 1 and type 2 file
  204. // email records, just to be sure.
  205. int len = mPhoneBookRecords.size();
  206. // Type 1 file, the number of records is the same as the number of
  207. // records in the ADN file.
  208. if (mEmailsForAdnRec == null) {
  209. parseType1EmailFile(len);
  210. }
  211. for (int i = 0; i < numAdnRecs; i++) {
  212. ArrayList<String> emailList = null;
  213. try {
  214. emailList = mEmailsForAdnRec.get(i);
  215. } catch (IndexOutOfBoundsException e) {
  216. break;
  217. }
  218. if (emailList == null) continue;
  219. AdnRecord rec = mPhoneBookRecords.get(i);
  220. String[] emails = new String[emailList.size()];
  221. System.arraycopy(emailList.toArray(), 0, emails, 0, emailList.size());
  222. rec.setEmails(emails);
  223. mPhoneBookRecords.set(i, rec);
  224. }
  225. }
  226. void parseType1EmailFile(int numRecs) {
  227. mEmailsForAdnRec = new HashMap<Integer, ArrayList<String>>();
  228. byte[] emailRec = null;
  229. for (int i = 0; i < numRecs; i++) {
  230. try {
  231. emailRec = mEmailFileRecord.get(i);
  232. } catch (IndexOutOfBoundsException e) {
  233. Log.e(LOG_TAG, "Error: Improper ICC card: No email record for ADN, continuing");
  234. break;
  235. }
  236. int adnRecNum = emailRec[emailRec.length - 1];
  237. if (adnRecNum == -1) {
  238. continue;
  239. }
  240. String email = readEmailRecord(i);
  241. if (email == null || email.equals("")) {
  242. continue;
  243. }
  244. // SIM record numbers are 1 based.
  245. ArrayList<String> val = mEmailsForAdnRec.get(adnRecNum - 1);
  246. if (val == null) {
  247. val = new ArrayList<String>();
  248. }
  249. val.add(email);
  250. // SIM record numbers are 1 based.
  251. mEmailsForAdnRec.put(adnRecNum - 1, val);
  252. }
  253. }
  254. private String readEmailRecord(int recNum) {
  255. byte[] emailRec = null;
  256. try {
  257. emailRec = mEmailFileRecord.get(recNum);
  258. } catch (IndexOutOfBoundsException e) {
  259. return null;
  260. }
  261. // The length of the record is X+2 byte, where X bytes is the email address
  262. String email = IccUtils.adnStringFieldToString(emailRec, 0, emailRec.length - 2);
  263. return email;
  264. }
  265. private void readAdnFileAndWait(int recNum) {
  266. Map <Integer,Integer> fileIds;
  267. fileIds = mPbrFile.mFileIds.get(recNum);
  268. if (fileIds == null || fileIds.isEmpty()) return;
  269. int extEf = 0;
  270. // Only call fileIds.get while EFEXT1_TAG is available
  271. if (fileIds.containsKey(USIM_EFEXT1_TAG)) {
  272. extEf = fileIds.get(USIM_EFEXT1_TAG);
  273. }
  274. mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
  275. extEf, obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
  276. try {
  277. mLock.wait();
  278. } catch (InterruptedException e) {
  279. Log.e(LOG_TAG, "Interrupted Exception in readAdnFileAndWait");
  280. }
  281. }
  282. private void createPbrFile(ArrayList<byte[]> records) {
  283. if (records == null) {
  284. mPbrFile = null;
  285. mIsPbrPresent = false;
  286. return;
  287. }
  288. mPbrFile = new PbrFile(records);
  289. }
  290. @Override
  291. public void handleMessage(Message msg) {
  292. AsyncResult ar;
  293. switch(msg.what) {
  294. case EVENT_PBR_LOAD_DONE:
  295. ar = (AsyncResult) msg.obj;
  296. if (ar.exception == null) {
  297. createPbrFile((ArrayList<byte[]>)ar.result);
  298. }
  299. synchronized (mLock) {
  300. mLock.notify();
  301. }
  302. break;
  303. case EVENT_USIM_ADN_LOAD_DONE:
  304. log("Loading USIM ADN records done");
  305. ar = (AsyncResult) msg.obj;
  306. if (ar.exception == null) {
  307. mPhoneBookRecords.addAll((ArrayList<AdnRecord>)ar.result);
  308. }
  309. synchronized (mLock) {
  310. mLock.notify();
  311. }
  312. break;
  313. case EVENT_IAP_LOAD_DONE:
  314. log("Loading USIM IAP records done");
  315. ar = (AsyncResult) msg.obj;
  316. if (ar.exception == null) {
  317. mIapFileRecord = ((ArrayList<byte[]>)ar.result);
  318. }
  319. synchronized (mLock) {
  320. mLock.notify();
  321. }
  322. break;
  323. case EVENT_EMAIL_LOAD_DONE:
  324. log("Loading USIM Email records done");
  325. ar = (AsyncResult) msg.obj;
  326. if (ar.exception == null) {
  327. mEmailFileRecord = ((ArrayList<byte[]>)ar.result);
  328. }
  329. synchronized (mLock) {
  330. mLock.notify();
  331. }
  332. break;
  333. }
  334. }
  335. private class PbrFile {
  336. // RecNum <EF Tag, efid>
  337. HashMap<Integer,Map<Integer,Integer>> mFileIds;
  338. PbrFile(ArrayList<byte[]> records) {
  339. mFileIds = new HashMap<Integer, Map<Integer, Integer>>();
  340. SimTlv recTlv;
  341. int recNum = 0;
  342. for (byte[] record: records) {
  343. recTlv = new SimTlv(record, 0, record.length);
  344. parseTag(recTlv, recNum);
  345. recNum ++;
  346. }
  347. }
  348. void parseTag(SimTlv tlv, int recNum) {
  349. SimTlv tlvEf;
  350. int tag;
  351. byte[] data;
  352. Map<Integer, Integer> val = new HashMap<Integer, Integer>();
  353. do {
  354. tag = tlv.getTag();
  355. switch(tag) {
  356. case USIM_TYPE1_TAG: // A8
  357. case USIM_TYPE3_TAG: // AA
  358. case USIM_TYPE2_TAG: // A9
  359. data = tlv.getData();
  360. tlvEf = new SimTlv(data, 0, data.length);
  361. parseEf(tlvEf, val, tag);
  362. break;
  363. }
  364. } while (tlv.nextObject());
  365. mFileIds.put(recNum, val);
  366. }
  367. void parseEf(SimTlv tlv, Map<Integer, Integer> val, int parentTag) {
  368. int tag;
  369. byte[] data;
  370. int tagNumberWithinParentTag = 0;
  371. do {
  372. tag = tlv.getTag();
  373. if (parentTag == USIM_TYPE2_TAG && tag == USIM_EFEMAIL_TAG) {
  374. mEmailPresentInIap = true;
  375. mEmailTagNumberInIap = tagNumberWithinParentTag;
  376. }
  377. switch(tag) {
  378. case USIM_EFEMAIL_TAG:
  379. case USIM_EFADN_TAG:
  380. case USIM_EFEXT1_TAG:
  381. case USIM_EFANR_TAG:
  382. case USIM_EFPBC_TAG:
  383. case USIM_EFGRP_TAG:
  384. case USIM_EFAAS_TAG:
  385. case USIM_EFGSD_TAG:
  386. case USIM_EFUID_TAG:
  387. case USIM_EFCCP1_TAG:
  388. case USIM_EFIAP_TAG:
  389. case USIM_EFSNE_TAG:
  390. data = tlv.getData();
  391. int efid = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
  392. val.put(tag, efid);
  393. break;
  394. }
  395. tagNumberWithinParentTag ++;
  396. } while(tlv.nextObject());
  397. }
  398. }
  399. private void log(String msg) {
  400. if(DBG) Log.d(LOG_TAG, msg);
  401. }
  402. }