From 1df6da9bfcb589ccf9f45c207fb1a64bd3f0f36e Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 31 Oct 2016 14:56:51 -0700 Subject: Cleanup of IccConstants and SIMRecords Constants -Fix formatting of IccConstants -Remove Base implementation for setMsisdnNumber() -Organize SIMRecord Message events by category Bug: 32277497 Test: none Change-Id: I929ed70b562dc19dfc95f2f69454d5876f97cff4 (cherry picked from commit d6a0c111d4737b4bd233ae6d2efcbc0a0cd1d755) --- .../internal/telephony/uicc/IccConstants.java | 42 ++++++------- .../internal/telephony/uicc/IccRecords.java | 33 ++-------- .../internal/telephony/uicc/SIMFileHandler.java | 2 - .../internal/telephony/uicc/SIMRecords.java | 70 ++++++++++++---------- 4 files changed, 65 insertions(+), 82 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccConstants.java b/src/java/com/android/internal/telephony/uicc/IccConstants.java index 061b28f8c..772516680 100644 --- a/src/java/com/android/internal/telephony/uicc/IccConstants.java +++ b/src/java/com/android/internal/telephony/uicc/IccConstants.java @@ -30,21 +30,21 @@ public interface IccConstants { static final int EF_EXT2 = 0x6F4B; static final int EF_EXT3 = 0x6F4C; static final int EF_EXT5 = 0x6F4E; - static final int EF_EXT6 = 0x6fc8; // Ext record for EF[MBDN] + static final int EF_EXT6 = 0x6FC8; // Ext record for EF[MBDN] static final int EF_MWIS = 0x6FCA; - static final int EF_MBDN = 0x6fc7; - static final int EF_PNN = 0x6fc5; - static final int EF_OPL = 0x6fc6; + static final int EF_MBDN = 0x6FC7; + static final int EF_PNN = 0x6FC5; + static final int EF_OPL = 0x6FC6; static final int EF_SPN = 0x6F46; static final int EF_SMS = 0x6F3C; - static final int EF_ICCID = 0x2fe2; + static final int EF_ICCID = 0x2FE2; static final int EF_AD = 0x6FAD; - static final int EF_MBI = 0x6fc9; - static final int EF_MSISDN = 0x6f40; - static final int EF_SPDI = 0x6fcd; - static final int EF_SST = 0x6f38; + static final int EF_MBI = 0x6FC9; + static final int EF_MSISDN = 0x6F40; + static final int EF_SPDI = 0x6FCD; + static final int EF_SST = 0x6F38; static final int EF_CFIS = 0x6FCB; - static final int EF_IMG = 0x4f20; + static final int EF_IMG = 0x4F20; // USIM SIM file ids from TS 131.102 public static final int EF_PBR = 0x4F30; @@ -54,13 +54,13 @@ public interface IccConstants { static final int EF_MAILBOX_CPHS = 0x6F17; static final int EF_VOICE_MAIL_INDICATOR_CPHS = 0x6F11; static final int EF_CFF_CPHS = 0x6F13; - static final int EF_SPN_CPHS = 0x6f14; - static final int EF_SPN_SHORT_CPHS = 0x6f18; - static final int EF_INFO_CPHS = 0x6f16; - static final int EF_CSP_CPHS = 0x6f15; + static final int EF_SPN_CPHS = 0x6F14; + static final int EF_SPN_SHORT_CPHS = 0x6F18; + static final int EF_INFO_CPHS = 0x6F16; + static final int EF_CSP_CPHS = 0x6F15; // CDMA RUIM file ids from 3GPP2 C.S0023-0 - static final int EF_CST = 0x6f32; + static final int EF_CST = 0x6F32; static final int EF_RUIM_SPN =0x6F41; // ETSI TS.102.221 @@ -75,12 +75,12 @@ public interface IccConstants { static final int EF_CSIM_MIPUPP = 0x6F4D; //ISIM access - static final int EF_IMPU = 0x6f04; - static final int EF_IMPI = 0x6f02; - static final int EF_DOMAIN = 0x6f03; - static final int EF_IST = 0x6f07; - static final int EF_PCSCF = 0x6f09; - static final int EF_PSI = 0x6fe5; + static final int EF_IMPU = 0x6F04; + static final int EF_IMPI = 0x6F02; + static final int EF_DOMAIN = 0x6F03; + static final int EF_IST = 0x6F07; + static final int EF_PCSCF = 0x6F09; + static final int EF_PSI = 0x6FE5; // SMS record length from TS 51.011 10.5.3 static public final int SMS_RECORD_LENGTH = 176; diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index af54e6b37..1c6fa9847 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -22,6 +22,7 @@ import android.os.Handler; import android.os.Message; import android.os.Registrant; import android.os.RegistrantList; + import android.telephony.Rlog; import android.telephony.SubscriptionInfo; import android.telephony.TelephonyManager; @@ -101,7 +102,6 @@ public abstract class IccRecords extends Handler implements IccConstants { public static final int SPN_RULE_SHOW_PLMN = 0x02; // ***** Event Constants - protected static final int EVENT_SET_MSISDN_DONE = 30; public static final int EVENT_MWI = 0; // Message Waiting indication public static final int EVENT_CFI = 1; // Call Forwarding indication public static final int EVENT_SPN = 2; // Service Provider Name @@ -320,34 +320,13 @@ public abstract class IccRecords extends Handler implements IccConstants { return null; } - /** - * Set subscriber number to SIM record - * - * The subscriber number is stored in EF_MSISDN (TS 51.011) - * - * When the operation is complete, onComplete will be sent to its handler - * - * @param alphaTag alpha-tagging of the dailing nubmer (up to 10 characters) - * @param number dailing nubmer (up to 20 digits) - * if the number starts with '+', then set to international TOA - * @param onComplete - * onComplete.obj will be an AsyncResult - * ((AsyncResult)onComplete.obj).exception == null on success - * ((AsyncResult)onComplete.obj).exception != null on fail - */ public void setMsisdnNumber(String alphaTag, String number, Message onComplete) { - - mMsisdn = number; - mMsisdnTag = alphaTag; - - if (DBG) log("Set MSISDN: " + mMsisdnTag +" " + mMsisdn); - - - AdnRecord adn = new AdnRecord(mMsisdnTag, mMsisdn); - - new AdnRecordLoader(mFh).updateEF(adn, EF_MSISDN, EF_EXT1, 1, null, - obtainMessage(EVENT_SET_MSISDN_DONE, onComplete)); + loge("setMsisdn() should not be invoked on base IccRecords"); + // synthesize a "File Not Found" exception and return it + AsyncResult.forMessage(onComplete).exception = + (new IccIoResult(0x6A, 0x82, (byte[]) null)).getException(); + onComplete.sendToTarget(); } public String getMsisdnAlphaTag() { diff --git a/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java b/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java index 8412b4eae..3be0c9914 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/SIMFileHandler.java @@ -56,8 +56,6 @@ public final class SIMFileHandler extends IccFileHandler implements IccConstants case EF_CFIS: case EF_GID1: case EF_GID2: - return MF_SIM + DF_GSM; - case EF_MAILBOX_CPHS: case EF_VOICE_MAIL_INDICATOR_CPHS: case EF_CFF_CPHS: diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index e936d85cf..c06d7fbd0 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -20,15 +20,15 @@ import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.res.Resources; import android.os.AsyncResult; import android.os.Message; import android.telephony.CarrierConfigManager; import android.telephony.PhoneNumberUtils; +import android.telephony.Rlog; import android.telephony.SmsMessage; import android.telephony.SubscriptionInfo; import android.text.TextUtils; -import android.telephony.Rlog; -import android.content.res.Resources; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.MccTable; @@ -138,36 +138,42 @@ public class SIMRecords extends IccRecords { private static final int CFIS_ADN_EXTENSION_ID_OFFSET = 15; // ***** Event Constants - private static final int EVENT_GET_IMSI_DONE = 3; - private static final int EVENT_GET_ICCID_DONE = 4; - private static final int EVENT_GET_MBI_DONE = 5; - private static final int EVENT_GET_MBDN_DONE = 6; - private static final int EVENT_GET_MWIS_DONE = 7; - private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8; - protected static final int EVENT_GET_AD_DONE = 9; // Admin data on SIM - protected static final int EVENT_GET_MSISDN_DONE = 10; - private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11; - private static final int EVENT_GET_SPN_DONE = 12; - private static final int EVENT_GET_SPDI_DONE = 13; - private static final int EVENT_UPDATE_DONE = 14; - private static final int EVENT_GET_PNN_DONE = 15; - protected static final int EVENT_GET_SST_DONE = 17; - private static final int EVENT_GET_ALL_SMS_DONE = 18; - private static final int EVENT_MARK_SMS_READ_DONE = 19; - private static final int EVENT_SET_MBDN_DONE = 20; - private static final int EVENT_SMS_ON_SIM = 21; - private static final int EVENT_GET_SMS_DONE = 22; - private static final int EVENT_GET_CFF_DONE = 24; - private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25; - private static final int EVENT_GET_INFO_CPHS_DONE = 26; - // private static final int EVENT_SET_MSISDN_DONE = 30; Defined in IccRecords as 30 - private static final int EVENT_SIM_REFRESH = 31; - private static final int EVENT_GET_CFIS_DONE = 32; - private static final int EVENT_GET_CSP_CPHS_DONE = 33; - private static final int EVENT_GET_GID1_DONE = 34; - private static final int EVENT_APP_LOCKED = 35; - private static final int EVENT_GET_GID2_DONE = 36; - private static final int EVENT_CARRIER_CONFIG_CHANGED = 37; + private static final int SIM_RECORD_EVENT_BASE = 0x00; + private static final int EVENT_GET_IMSI_DONE = 3 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_ICCID_DONE = 4 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_MBI_DONE = 5 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_MBDN_DONE = 6 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_MWIS_DONE = 7 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE = 8 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_AD_DONE = 9 + SIM_RECORD_EVENT_BASE; // Admin data on SIM + private static final int EVENT_GET_MSISDN_DONE = 10 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CPHS_MAILBOX_DONE = 11 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SPN_DONE = 12 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SPDI_DONE = 13 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_UPDATE_DONE = 14 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_PNN_DONE = 15 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SST_DONE = 17 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_ALL_SMS_DONE = 18 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_MARK_SMS_READ_DONE = 19 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SET_MBDN_DONE = 20 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SMS_ON_SIM = 21 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_SMS_DONE = 22 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CFF_DONE = 24 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SET_CPHS_MAILBOX_DONE = 25 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_INFO_CPHS_DONE = 26 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_SET_MSISDN_DONE = 30 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CFIS_DONE = 32 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_CSP_CPHS_DONE = 33 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_GID1_DONE = 34 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_GID2_DONE = 36 + SIM_RECORD_EVENT_BASE; + + // TODO: Possibly move these to IccRecords.java + private static final int SYSTEM_EVENT_BASE = 0x100; + private static final int EVENT_CARRIER_CONFIG_CHANGED = 1 + SYSTEM_EVENT_BASE; + private static final int EVENT_APP_LOCKED = 2 + SYSTEM_EVENT_BASE; + private static final int EVENT_SIM_REFRESH = 3 + SYSTEM_EVENT_BASE; + + // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length. -- cgit v1.2.3 From 4a1959c22e94e69040b6cab21fa08ca2e1df0c9b Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Thu, 3 Nov 2016 13:04:21 -0700 Subject: Add meaningful error strings to IccIoResult Bug: 32641276 Test: none Change-Id: I8c3e9068f7ece1fb90b73da556add060c9484f28 --- .../internal/telephony/uicc/IccIoResult.java | 145 ++++++++++++++++++++- 1 file changed, 143 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/internal/telephony/uicc/IccIoResult.java b/src/java/com/android/internal/telephony/uicc/IccIoResult.java index 6f0b5c3fd..4a35e1460 100644 --- a/src/java/com/android/internal/telephony/uicc/IccIoResult.java +++ b/src/java/com/android/internal/telephony/uicc/IccIoResult.java @@ -22,6 +22,147 @@ package com.android.internal.telephony.uicc; */ public class IccIoResult { + + private static final String UNKNOWN_ERROR = "unknown"; + + private String getErrorString() { + // Errors from 3gpp 11.11 9.4.1 + // Additional Errors from ETSI 102.221 + // + // All error codes below are copied directly from their respective specification + // without modification except in cases where necessary string formatting has been omitted. + switch(sw1) { + case 0x62: + switch(sw2) { + case 0x00: return "No information given," + + " state of non volatile memory unchanged"; + case 0x81: return "Part of returned data may be corrupted"; + case 0x82: return "End of file/record reached before reading Le bytes"; + case 0x83: return "Selected file invalidated"; + case 0x84: return "Selected file in termination state"; + case 0xF1: return "More data available"; + case 0xF2: return "More data available and proactive command pending"; + case 0xF3: return "Response data available"; + } + break; + case 0x63: + if (sw2 >> 4 == 0x0C) { + return "Command successful but after using an internal" + + "update retry routine but Verification failed"; + } + switch(sw2) { + case 0xF1: return "More data expected"; + case 0xF2: return "More data expected and proactive command pending"; + } + break; + case 0x64: + switch(sw2) { + case 0x00: return "No information given," + + " state of non-volatile memory unchanged"; + } + break; + case 0x65: + switch(sw2) { + case 0x00: return "No information given, state of non-volatile memory changed"; + case 0x81: return "Memory problem"; + } + break; + case 0x67: + switch(sw2) { + case 0x00: return "incorrect parameter P3"; + default: return "The interpretation of this status word is command dependent"; + } + // break; + case 0x6B: return "incorrect parameter P1 or P2"; + case 0x6D: return "unknown instruction code given in the command"; + case 0x6E: return "wrong instruction class given in the command"; + case 0x6F: + switch(sw2) { + case 0x00: return "technical problem with no diagnostic given"; + default: return "The interpretation of this status word is command dependent"; + } + // break; + case 0x68: + switch(sw2) { + case 0x00: return "No information given"; + case 0x81: return "Logical channel not supported"; + case 0x82: return "Secure messaging not supported"; + } + break; + case 0x69: + switch(sw2) { + case 0x00: return "No information given"; + case 0x81: return "Command incompatible with file structure"; + case 0x82: return "Security status not satisfied"; + case 0x83: return "Authentication/PIN method blocked"; + case 0x84: return "Referenced data invalidated"; + case 0x85: return "Conditions of use not satisfied"; + case 0x86: return "Command not allowed (no EF selected)"; + case 0x89: return "Command not allowed - secure channel -" + + " security not satisfied"; + } + break; + case 0x6A: + switch(sw2) { + case 0x80: return "Incorrect parameters in the data field"; + case 0x81: return "Function not supported"; + case 0x82: return "File not found"; + case 0x83: return "Record not found"; + case 0x84: return "Not enough memory space"; + case 0x86: return "Incorrect parameters P1 to P2"; + case 0x87: return "Lc inconsistent with P1 to P2"; + case 0x88: return "Referenced data not found"; + } + break; + case 0x90: return null; // success + case 0x91: return null; // success + //Status Code 0x92 has contradictory meanings from 11.11 and 102.221 10.2.1.1 + case 0x92: + if (sw2 >> 4 == 0) { + return "command successful but after using an internal update retry routine"; + } + switch(sw2) { + case 0x40: return "memory problem"; + } + break; + case 0x93: + switch(sw2) { + case 0x00: + return "SIM Application Toolkit is busy. Command cannot be executed" + + " at present, further normal commands are allowed."; + } + break; + case 0x94: + switch(sw2) { + case 0x00: return "no EF selected"; + case 0x02: return "out f range (invalid address)"; + case 0x04: return "file ID not found/pattern not found"; + case 0x08: return "file is inconsistent with the command"; + } + break; + case 0x98: + switch(sw2) { + case 0x02: return "no CHV initialized"; + case 0x04: return "access condition not fulfilled/" + + "unsuccessful CHV verification, at least one attempt left/" + + "unsuccessful UNBLOCK CHV verification, at least one attempt left/" + + "authentication failed"; + case 0x08: return "in contradiction with CHV status"; + case 0x10: return "in contradiction with invalidation status"; + case 0x40: return "unsuccessful CHV verification, no attempt left/" + + "unsuccessful UNBLOCK CHV verification, no attempt left/" + + "CHV blocked" + + "UNBLOCK CHV blocked"; + case 0x50: return "increase cannot be performed, Max value reached"; + } + break; + case 0x9E: return null; // success + case 0x9F: return null; // success + } + return UNKNOWN_ERROR; + } + + public int sw1; public int sw2; @@ -39,8 +180,8 @@ IccIoResult { @Override public String toString() { - return "IccIoResponse sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" - + Integer.toHexString(sw2); + return "IccIoResult sw1:0x" + Integer.toHexString(sw1) + " sw2:0x" + + Integer.toHexString(sw2) + ((!success()) ? " Error: " + getErrorString() : ""); } /** -- cgit v1.2.3 From 229d3318ca022dcda540a86b9f60bb314c78998b Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 31 Oct 2016 16:27:34 -0700 Subject: Add PLMN Selection Info to SIM Records Pull new paramters from SIMs and add them to SIMRecords dumpsys for debugging purposes. -Add OPLMNw/ACT -Add HPLMNw/ACT -Add FPLMN -Add PLMNw/ACT Bug: 32277497 Test: none Change-Id: I28bd67e3667d5c6ba1046c43f24d8e02ce7b8313 --- .../internal/telephony/uicc/IccConstants.java | 15 +++ .../internal/telephony/uicc/IccFileHandler.java | 8 +- .../internal/telephony/uicc/IccRecords.java | 7 + .../android/internal/telephony/uicc/IccUtils.java | 23 ++++ .../internal/telephony/uicc/PlmnActRecord.java | 144 +++++++++++++++++++++ .../internal/telephony/uicc/SIMRecords.java | 121 +++++++++++++++++ .../internal/telephony/uicc/UsimFileHandler.java | 7 + 7 files changed, 324 insertions(+), 1 deletion(-) create mode 100644 src/java/com/android/internal/telephony/uicc/PlmnActRecord.java diff --git a/src/java/com/android/internal/telephony/uicc/IccConstants.java b/src/java/com/android/internal/telephony/uicc/IccConstants.java index 772516680..970bf358e 100644 --- a/src/java/com/android/internal/telephony/uicc/IccConstants.java +++ b/src/java/com/android/internal/telephony/uicc/IccConstants.java @@ -82,6 +82,21 @@ public interface IccConstants { static final int EF_PCSCF = 0x6F09; static final int EF_PSI = 0x6FE5; + //PLMN Selection Information w/ Access Technology TS 131.102 + static final int EF_PLMN_W_ACT = 0x6F60; + static final int EF_OPLMN_W_ACT = 0x6F61; + static final int EF_HPLMN_W_ACT = 0x6F62; + + //Equivalent Home and Forbidden PLMN Lists TS 131.102 + static final int EF_EHPLMN = 0x6FD9; + static final int EF_FPLMN = 0x6F7B; + + // Last Roaming Selection Indicator + static final int EF_LRPLMNSI = 0x6FDC; + + //Search interval for higher priority PLMNs + static final int EF_HPPLMN = 0x6F31; + // SMS record length from TS 51.011 10.5.3 static public final int SMS_RECORD_LENGTH = 176; // SMS record length from C.S0023 3.4.27 diff --git a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java index 881b4c3e6..4750814ff 100644 --- a/src/java/com/android/internal/telephony/uicc/IccFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/IccFileHandler.java @@ -17,6 +17,7 @@ package com.android.internal.telephony.uicc; import android.os.*; + import com.android.internal.telephony.CommandsInterface; import java.util.ArrayList; @@ -25,6 +26,7 @@ import java.util.ArrayList; * {@hide} */ public abstract class IccFileHandler extends Handler implements IccConstants { + private static final boolean VDBG = false; //from TS 11.11 9.1 or elsewhere static protected final int COMMAND_READ_BINARY = 0xb0; @@ -516,6 +518,11 @@ public abstract class IccFileHandler extends Handler implements IccConstants { fileid = msg.arg1; + if (VDBG) { + logd(String.format("Contents of the Select Response for command %x: ", fileid) + + IccUtils.bytesToHexString(data)); + } + if (TYPE_EF != data[RESPONSE_DATA_FILE_TYPE]) { throw new IccFileTypeMismatch(); } @@ -628,7 +635,6 @@ public abstract class IccFileHandler extends Handler implements IccConstants { protected abstract String getEFPath(int efid); protected abstract void logd(String s); - protected abstract void loge(String s); } diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index 1c6fa9847..6bbecfe85 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -89,6 +89,13 @@ public abstract class IccRecords extends Handler implements IccConstants { protected String mGid2; protected String mPrefLang; + protected PlmnActRecord[] mHplmnActRecords; + protected PlmnActRecord[] mOplmnActRecords; + protected PlmnActRecord[] mPlmnActRecords; + + protected String[] mEhplmns; + protected String[] mFplmns; + private final Object mLock = new Object(); // ***** Constants diff --git a/src/java/com/android/internal/telephony/uicc/IccUtils.java b/src/java/com/android/internal/telephony/uicc/IccUtils.java index fdcc12537..67de87f2b 100644 --- a/src/java/com/android/internal/telephony/uicc/IccUtils.java +++ b/src/java/com/android/internal/telephony/uicc/IccUtils.java @@ -23,6 +23,7 @@ import android.graphics.Color; import android.telephony.Rlog; import com.android.internal.telephony.GsmAlphabet; + import java.io.UnsupportedEncodingException; /** @@ -60,6 +61,28 @@ public class IccUtils { return ret.toString(); } + /** + * PLMN (MCC/MNC) is encoded as per 24.008 10.5.1.3 + * Returns a concatenated string of MCC+MNC, stripping + * a trailing character for a 2-digit MNC + */ + public static String bcdPlmnToString(byte[] data, int offset) { + if (offset + 3 > data.length) { + return null; + } + byte[] trans = new byte[3]; + trans[0] = (byte) ((data[0 + offset] << 4) | ((data[0 + offset] >> 4) & 0xF)); + trans[1] = (byte) ((data[1 + offset] << 4) | (data[2 + offset] & 0xF)); + trans[2] = (byte) ((data[2 + offset] & 0xF0) | ((data[1 + offset] >> 4) & 0xF)); + String ret = bytesToHexString(trans); + + // For a 2-digit MNC we trim the trailing 'f' + if (ret.endsWith("f")) { + ret = ret.substring(0, ret.length() - 1); + } + return ret; + } + /** * Some fields (like ICC ID) in GSM SIMs are stored as nibble-swizzled BCH */ diff --git a/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java b/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java new file mode 100644 index 000000000..a4cf7cc1c --- /dev/null +++ b/src/java/com/android/internal/telephony/uicc/PlmnActRecord.java @@ -0,0 +1,144 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.telephony.uicc; + +import android.os.Parcel; +import android.os.Parcelable; +import android.telephony.Rlog; + +import java.util.Arrays; + +/** + * {@hide} + */ +public class PlmnActRecord implements Parcelable { + private static final String LOG_TAG = "PlmnActRecord"; + + // Values specified in 3GPP 31.102 sec. 4.2.5 + public static final int ACCESS_TECH_UTRAN = 0x8000; + public static final int ACCESS_TECH_EUTRAN = 0x4000; + public static final int ACCESS_TECH_GSM = 0x0080; + public static final int ACCESS_TECH_GSM_COMPACT = 0x0040; + public static final int ACCESS_TECH_CDMA2000_HRPD = 0x0020; + public static final int ACCESS_TECH_CDMA2000_1XRTT = 0x0010; + public static final int ACCESS_TECH_RESERVED = 0x3F0F; + + public static final int ENCODED_LENGTH = 5; + + public final String plmn; + public final int accessTechs; + + private static final boolean VDBG = true; + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public PlmnActRecord createFromParcel(Parcel source) { + return new PlmnActRecord(source.readString(), source.readInt()); + } + + @Override + public PlmnActRecord[] newArray(int size) { + return new PlmnActRecord[size]; + } + }; + + /* From 3gpp 31.102 section 4.2.5 + * Bytes 0-2 bcd-encoded PLMN-ID + * Bytes 3-4 bitfield of access technologies + */ + public PlmnActRecord(byte[] bytes, int offset) { + if (VDBG) Rlog.v(LOG_TAG, "Creating PlmnActRecord " + offset); + this.plmn = IccUtils.bcdPlmnToString(bytes, offset); + this.accessTechs = ((int) bytes[offset + 3] << 8) | bytes[offset + 4]; + } + + private PlmnActRecord(String plmn, int accessTechs) { + this.plmn = plmn; + this.accessTechs = accessTechs; + } + + private String accessTechString() { + if (accessTechs == 0) { + return "NONE"; + } + + StringBuilder sb = new StringBuilder(); + if ((accessTechs & ACCESS_TECH_UTRAN) != 0) { + sb.append("UTRAN|"); + } + if ((accessTechs & ACCESS_TECH_EUTRAN) != 0) { + sb.append("EUTRAN|"); + } + if ((accessTechs & ACCESS_TECH_GSM) != 0) { + sb.append("GSM|"); + } + if ((accessTechs & ACCESS_TECH_GSM_COMPACT) != 0) { + sb.append("GSM_COMPACT|"); + } + if ((accessTechs & ACCESS_TECH_CDMA2000_HRPD) != 0) { + sb.append("CDMA2000_HRPD|"); + } + if ((accessTechs & ACCESS_TECH_CDMA2000_1XRTT) != 0) { + sb.append("CDMA2000_1XRTT|"); + } + if ((accessTechs & ACCESS_TECH_RESERVED) != 0) { + sb.append(String.format("UNKNOWN:%x|", accessTechs & ACCESS_TECH_RESERVED)); + } + // Trim the tailing pipe character + return sb.substring(0, sb.length() - 1); + } + + @Override + public String toString() { + return String.format("{PLMN=%s,AccessTechs=%s}", plmn, accessTechString()); + } + + /** + * Convenience method for extracting all records from encoded bytes + */ + public static PlmnActRecord[] getRecords(byte[] recordBytes) { + if (recordBytes == null || recordBytes.length == 0 + || recordBytes.length % ENCODED_LENGTH != 0) { + Rlog.e(LOG_TAG, "Malformed PlmnActRecord, bytes: " + + ((recordBytes != null) ? Arrays.toString(recordBytes) : null)); + return null; + } + int numRecords = recordBytes.length / ENCODED_LENGTH; + if (VDBG) Rlog.v(LOG_TAG, "Extracting Logs, count=" + numRecords); + + PlmnActRecord[] records = new PlmnActRecord[numRecords]; + + for(int i = 0; i < numRecords; i++) { + records[i] = new PlmnActRecord(recordBytes, i * ENCODED_LENGTH); + } + return records; + } + + // Parcelable Implementation + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(plmn); + dest.writeInt(accessTechs); + } + +} diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index c06d7fbd0..96311b382 100644 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -51,6 +51,8 @@ public class SIMRecords extends IccRecords { private static final boolean CRASH_RIL = false; + private static final boolean VDBG = false; + // ***** Instance Variables VoiceMailConstants mVmConfig; @@ -166,6 +168,11 @@ public class SIMRecords extends IccRecords { private static final int EVENT_GET_CSP_CPHS_DONE = 33 + SIM_RECORD_EVENT_BASE; private static final int EVENT_GET_GID1_DONE = 34 + SIM_RECORD_EVENT_BASE; private static final int EVENT_GET_GID2_DONE = 36 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_PLMN_W_ACT_DONE = 37 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_OPLMN_W_ACT_DONE = 38 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_HPLMN_W_ACT_DONE = 39 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_EHPLMN_DONE = 40 + SIM_RECORD_EVENT_BASE; + private static final int EVENT_GET_FPLMN_DONE = 41 + SIM_RECORD_EVENT_BASE; // TODO: Possibly move these to IccRecords.java private static final int SYSTEM_EVENT_BASE = 0x100; @@ -268,6 +275,11 @@ public class SIMRecords extends IccRecords { mPnnHomeName = null; mGid1 = null; mGid2 = null; + mPlmnActRecords = null; + mOplmnActRecords = null; + mHplmnActRecords = null; + mFplmns = null; + mEhplmns = null; mAdnCache.reset(); @@ -1246,6 +1258,76 @@ public class SIMRecords extends IccRecords { break; + case EVENT_GET_PLMN_W_ACT_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + + if (ar.exception != null || data == null) { + loge("Failed getting User PLMN with Access Tech Records: " + ar.exception); + break; + } else { + log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data)); + mPlmnActRecords = PlmnActRecord.getRecords(data); + if (VDBG) log("PlmnActRecords=" + Arrays.toString(mPlmnActRecords)); + } + break; + + case EVENT_GET_OPLMN_W_ACT_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + + if (ar.exception != null || data == null) { + loge("Failed getting Operator PLMN with Access Tech Records: " + + ar.exception); + break; + } else { + log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data)); + mOplmnActRecords = PlmnActRecord.getRecords(data); + if (VDBG) log("OplmnActRecord[]=" + Arrays.toString(mOplmnActRecords)); + } + break; + + case EVENT_GET_HPLMN_W_ACT_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + + if (ar.exception != null || data == null) { + loge("Failed getting Home PLMN with Access Tech Records: " + ar.exception); + break; + } else { + log("Received a PlmnActRecord, raw=" + IccUtils.bytesToHexString(data)); + mHplmnActRecords = PlmnActRecord.getRecords(data); + log("HplmnActRecord[]=" + Arrays.toString(mHplmnActRecords)); + } + break; + + case EVENT_GET_EHPLMN_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + if (ar.exception != null || data == null) { + loge("Failed getting Equivalent Home PLMNs: " + ar.exception); + break; + } else { + mEhplmns = parseBcdPlmnList(data, "Equivalent Home"); + } + break; + + case EVENT_GET_FPLMN_DONE: + isRecordLoadResponse = true; + ar = (AsyncResult) msg.obj; + data = (byte[]) ar.result; + if (ar.exception != null || data == null) { + loge("Failed getting Forbidden PLMNs: " + ar.exception); + break; + } else { + mFplmns = parseBcdPlmnList(data, "Forbidden"); + } + break; + case EVENT_CARRIER_CONFIG_CHANGED: handleCarrierNameOverride(); break; @@ -1640,6 +1722,21 @@ public class SIMRecords extends IccRecords { mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); mRecordsToLoad++; + mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE)); + mRecordsToLoad++; + + mFh.loadEFTransparent(EF_OPLMN_W_ACT, obtainMessage(EVENT_GET_OPLMN_W_ACT_DONE)); + mRecordsToLoad++; + + mFh.loadEFTransparent(EF_HPLMN_W_ACT, obtainMessage(EVENT_GET_HPLMN_W_ACT_DONE)); + mRecordsToLoad++; + + mFh.loadEFTransparent(EF_EHPLMN, obtainMessage(EVENT_GET_EHPLMN_DONE)); + mRecordsToLoad++; + + mFh.loadEFTransparent(EF_FPLMN, obtainMessage(EVENT_GET_FPLMN_DONE)); + mRecordsToLoad++; + loadEfLiAndEfPl(); // XXX should seek instead of examining them all @@ -1915,6 +2012,25 @@ public class SIMRecords extends IccRecords { } } + /** + * convert a byte array of packed plmns to an array of strings + */ + private String[] parseBcdPlmnList(byte[] data, String description) { + final int packedBcdPlmnLenBytes = 3; + log("Received " + description + " PLMNs, raw=" + IccUtils.bytesToHexString(data)); + if (data.length == 0 || (data.length % packedBcdPlmnLenBytes) != 0) { + loge("Received invalid " + description + " PLMN list"); + return null; + } + int numPlmns = data.length / packedBcdPlmnLenBytes; + String[] ret = new String[numPlmns]; + for (int i = 0; i < numPlmns; i++) { + ret[i] = IccUtils.bcdPlmnToString(data, i * packedBcdPlmnLenBytes); + } + if (VDBG) logv(description + " PLMNs: " + Arrays.toString(ret)); + return ret; + } + /** * check to see if Mailbox Number is allocated and activated in CPHS SST */ @@ -2012,6 +2128,11 @@ public class SIMRecords extends IccRecords { pw.println(" mUsimServiceTable=" + mUsimServiceTable); pw.println(" mGid1=" + mGid1); pw.println(" mGid2=" + mGid2); + pw.println(" mPlmnActRecords[]=" + Arrays.toString(mPlmnActRecords)); + pw.println(" mOplmnActRecords[]=" + Arrays.toString(mOplmnActRecords)); + pw.println(" mHplmnActRecords[]=" + Arrays.toString(mHplmnActRecords)); + pw.println(" mFplmns[]=" + Arrays.toString(mFplmns)); + pw.println(" mEhplmns[]=" + Arrays.toString(mEhplmns)); pw.flush(); } } diff --git a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java index bd3357ee6..f2834f7ec 100644 --- a/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java +++ b/src/java/com/android/internal/telephony/uicc/UsimFileHandler.java @@ -61,6 +61,13 @@ public final class UsimFileHandler extends IccFileHandler implements IccConstant case EF_GID1: case EF_GID2: case EF_LI: + case EF_PLMN_W_ACT: + case EF_OPLMN_W_ACT: + case EF_HPLMN_W_ACT: + case EF_EHPLMN: + case EF_FPLMN: + case EF_LRPLMNSI: + case EF_HPPLMN: return MF_SIM + DF_ADF; case EF_PBR: -- cgit v1.2.3