PageRenderTime 51ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/frameworks/opt/telephony/src/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java

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