aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShantur Rathore <shantur.rathore@gmail.com>2014-12-03 16:20:10 +0000
committerMichael Bestas <mikeioannina@gmail.com>2017-01-07 01:41:40 +0200
commitc503796618c6e5981e3a4d37ce5027e6ab0f2809 (patch)
treecfad824fc0491472b427a0e205d35a923fa38fea
parent282a197761505a32acffc2d9029a7c5f5a7134fd (diff)
downloadandroid_frameworks_opt_telephony-c503796618c6e5981e3a4d37ce5027e6ab0f2809.tar.gz
android_frameworks_opt_telephony-c503796618c6e5981e3a4d37ce5027e6ab0f2809.tar.bz2
android_frameworks_opt_telephony-c503796618c6e5981e3a4d37ce5027e6ab0f2809.zip
Implement UICC TLV Data decoding.
Some phones / SIMs returns data in TLV format as decribed in ETSI TS 102 221 11.1.1 This enables parsing of TLV data if it finds one. This fixes reading of SIM_IO data like ICCID, MSISDN, etc on affected SIMs. In CM-12 this is needed for phone to function properly. In CM-12 Multisim support requires ICCID. If ICCID is not found then user is unable to make any outgoing calls. User is shown "Call not sent" error. Change-Id: I0fe20a9ec4cdd6021e7cb614ae578bc1c2c1d1fd (cherry picked from commit 70a14292e926db8694c03ac21956eb1c8c0b9cc5)
-rw-r--r--src/java/com/android/internal/telephony/uicc/IccFileHandler.java91
-rw-r--r--src/java/com/android/internal/telephony/uicc/UiccTlvData.java154
2 files changed, 217 insertions, 28 deletions
diff --git a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java
index 881b4c3e6..54e05f7ca 100644
--- a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java
+++ b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java
@@ -289,7 +289,7 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
fileid, 0, onLoaded);
mCi.iccIOForApp(COMMAND_GET_RESPONSE, fileid, getEFPath(fileid),
- 0, 0, GET_RESPONSE_EF_SIZE_BYTES, null, null, mAid, response);
+ 0, 0, 0, null, null, mAid, response);
}
/**
@@ -447,16 +447,29 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
data = result.payload;
- if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
- EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
- throw new IccFileTypeMismatch();
- }
+ if (UiccTlvData.isUiccTlvData(data)) {
+ UiccTlvData tlvData = UiccTlvData.parse(data);
- recordSize = new int[3];
- recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
- recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
- + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
- recordSize[2] = recordSize[1] / recordSize[0];
+ if (tlvData.isIncomplete()) {
+ throw new IccFileTypeMismatch();
+ }
+
+ recordSize = new int[3];
+ recordSize[0] = tlvData.mRecordSize;
+ recordSize[1] = tlvData.mFileSize;
+ recordSize[2] = tlvData.mNumRecords;
+ } else {
+ if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE] ||
+ EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
+ throw new IccFileTypeMismatch();
+ }
+
+ recordSize = new int[3];
+ recordSize[0] = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
+ recordSize[1] = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
+ + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
+ recordSize[2] = recordSize[1] / recordSize[0];
+ }
sendResult(response, recordSize, null);
break;
@@ -475,20 +488,32 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
data = result.payload;
path = lc.mPath;
- if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
- throw new IccFileTypeMismatch();
- }
+ if (UiccTlvData.isUiccTlvData(data)) {
+ UiccTlvData tlvData = UiccTlvData.parse(data);
- if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
- throw new IccFileTypeMismatch();
- }
+ if (tlvData.isIncomplete()) {
+ throw new IccFileTypeMismatch();
+ }
+
+ lc.mRecordSize = tlvData.mRecordSize;
+ lc.mCountRecords = tlvData.mNumRecords;
+ size = tlvData.mFileSize;
+ } else {
+ if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
+ throw new IccFileTypeMismatch();
+ }
+
+ if (EF_TYPE_LINEAR_FIXED != data[RESPONSE_DATA_STRUCTURE]) {
+ throw new IccFileTypeMismatch();
+ }
- lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
+ lc.mRecordSize = data[RESPONSE_DATA_RECORD_LENGTH] & 0xFF;
- size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
- + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
+ size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
+ + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
- lc.mCountRecords = size / lc.mRecordSize;
+ lc.mCountRecords = size / lc.mRecordSize;
+ }
if (lc.mLoadAll) {
lc.results = new ArrayList<byte[]>(lc.mCountRecords);
@@ -516,16 +541,26 @@ public abstract class IccFileHandler extends Handler implements IccConstants {
fileid = msg.arg1;
- if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
- throw new IccFileTypeMismatch();
- }
+ if (UiccTlvData.isUiccTlvData(data)) {
+ UiccTlvData tlvData = UiccTlvData.parse(data);
- if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
- throw new IccFileTypeMismatch();
- }
+ if (tlvData.mFileSize < 0) {
+ throw new IccFileTypeMismatch();
+ }
- size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
- + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
+ size = tlvData.mFileSize;
+ } else {
+ if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) {
+ throw new IccFileTypeMismatch();
+ }
+
+ if (EF_TYPE_TRANSPARENT != data[RESPONSE_DATA_STRUCTURE]) {
+ throw new IccFileTypeMismatch();
+ }
+
+ size = ((data[RESPONSE_DATA_FILE_SIZE_1] & 0xff) << 8)
+ + (data[RESPONSE_DATA_FILE_SIZE_2] & 0xff);
+ }
mCi.iccIOForApp(COMMAND_READ_BINARY, fileid, getEFPath(fileid),
0, 0, size, null, null, mAid,
diff --git a/src/java/com/android/internal/telephony/uicc/UiccTlvData.java b/src/java/com/android/internal/telephony/uicc/UiccTlvData.java
new file mode 100644
index 000000000..5f35e41d6
--- /dev/null
+++ b/src/java/com/android/internal/telephony/uicc/UiccTlvData.java
@@ -0,0 +1,154 @@
+package com.android.internal.telephony.uicc;
+
+/**
+ * UICC TLV Data Parser according to ETSI TS 102 221 spec.
+ */
+public class UiccTlvData {
+
+ private static final int TLV_FORMAT_ID = 0x62;
+
+ private static final int TAG_FILE_DESCRIPTOR = 0x82;
+ private static final int TAG_FILE_IDENTIFIER = 0x83;
+ private static final int TAG_PROPRIETARY_INFO = 0xA5;
+ private static final int TAG_LIFECYCLE_STATUS = 0x8A;
+ private static final int TAG_SECURITY_ATTR_1 = 0x8B;
+ private static final int TAG_SECURITY_ATTR_2 = 0x8C;
+ private static final int TAG_SECURITY_ATTR_3 = 0xAB;
+ private static final int TAG_FILE_SIZE = 0x80;
+ private static final int TAG_TOTAL_FILE_SIZE = 0x81;
+ private static final int TAG_SHORT_FILE_IDENTIFIER = 0x88;
+
+ private static final int TYPE_5 = 5;
+ private static final int TYPE_2 = 2;
+
+ int mRecordSize;
+ int mFileSize;
+ int mNumRecords;
+ boolean mIsDataEnough;
+
+ private int mFileType = -1;
+
+ private UiccTlvData() {
+ mNumRecords = -1;
+ mFileSize = -1;
+ mRecordSize = -1;
+ }
+
+ public boolean isIncomplete() {
+ return mNumRecords == -1 || mFileSize == -1 || mRecordSize == -1 || mFileType == -1;
+ }
+
+ public static boolean isUiccTlvData(byte[] data) {
+ if(data != null && data.length > 0 && TLV_FORMAT_ID == (data[0] & 0xFF)) {
+ return true;
+ }
+ return false;
+ }
+
+ public static UiccTlvData parse(byte[] data) throws IccFileTypeMismatch{
+
+ UiccTlvData parsedData = new UiccTlvData();
+
+ if (data == null || data.length == 0 || TLV_FORMAT_ID != (data[0] & 0xFF)) {
+ throw new IccFileTypeMismatch();
+ }
+
+ try {
+
+ int currentLocation = 2; //Ignore FCP size
+ int currentTag;
+
+ while (currentLocation < data.length) {
+ currentTag = data[currentLocation++] & 0xFF;
+
+ switch (currentTag) {
+ case TAG_FILE_DESCRIPTOR:
+ currentLocation = parsedData.parseFileDescriptor(data, currentLocation);
+ break;
+
+ case TAG_FILE_SIZE:
+ currentLocation = parsedData.parseFileSize(data, currentLocation);
+ break;
+
+ case TAG_FILE_IDENTIFIER:
+ case TAG_PROPRIETARY_INFO:
+ case TAG_LIFECYCLE_STATUS:
+ case TAG_SECURITY_ATTR_1:
+ case TAG_SECURITY_ATTR_2:
+ case TAG_SECURITY_ATTR_3:
+ case TAG_TOTAL_FILE_SIZE:
+ case TAG_SHORT_FILE_IDENTIFIER:
+ currentLocation = parsedData.parseSomeTag(data, currentLocation);
+ break;
+
+ default:
+ //Unknown TAG
+ throw new IccFileTypeMismatch();
+
+ }
+ }
+
+ } catch (ArrayIndexOutOfBoundsException e) {
+
+ //We might be looking at incomplete data but we might have what we need.
+ //Ignore this and let caller handle it by checking isIncomplete
+ }
+
+ return parsedData;
+ }
+
+ private int parseFileSize(byte[] data, int currentLocation) {
+ int length = data[currentLocation++] & 0xFF;
+
+ int fileSize = 0;
+ for (int i = 0; i < length; i++) {
+ fileSize += ((data[currentLocation + i] & 0xFF) << ( 8 * (length - i - 1)));
+ }
+
+ mFileSize = fileSize;
+
+ if (mFileType == TYPE_2) {
+ mRecordSize = fileSize;
+ }
+
+ return currentLocation + length;
+ }
+
+ private int parseSomeTag(byte[] data, int currentLocation) {
+ //Just skip unwanted tags;
+ int length = data[currentLocation++] & 0xFF;
+ return currentLocation + length;
+ }
+
+ private int parseFileDescriptor(byte[] data, int currentLocation) throws IccFileTypeMismatch {
+ int length = data[currentLocation++] & 0xFF;
+ if (length == 5) {
+
+ mRecordSize = ((data[currentLocation + 2] & 0xFF) << 8) +
+ (data[currentLocation + 3] & 0xFF); // Length of 1 record
+ mNumRecords = data[currentLocation + 4] & 0xFF; // Number of records
+
+ mFileSize = mRecordSize * mNumRecords;
+
+ mFileType = TYPE_5;
+
+ return currentLocation + 5;
+ } else if (length == 2) {
+
+ int descriptorByte = data[currentLocation + 1] & 0xFF;
+
+ //Ignore descriptorByte for now
+
+ mNumRecords = 1;
+
+ mFileType = TYPE_2;
+
+ return currentLocation + 2;
+
+ } else {
+ throw new IccFileTypeMismatch();
+ }
+ }
+
+}
+