diff options
author | Nathan Harold <nharold@google.com> | 2016-10-31 16:27:34 -0700 |
---|---|---|
committer | Nathan Harold <nharold@google.com> | 2016-12-05 15:20:06 -0800 |
commit | 229d3318ca022dcda540a86b9f60bb314c78998b (patch) | |
tree | 97c9186cd6913300364d0a3a444eb8950fd8ae3a | |
parent | 4a1959c22e94e69040b6cab21fa08ca2e1df0c9b (diff) | |
download | android_frameworks_opt_telephony-229d3318ca022dcda540a86b9f60bb314c78998b.tar.gz android_frameworks_opt_telephony-229d3318ca022dcda540a86b9f60bb314c78998b.tar.bz2 android_frameworks_opt_telephony-229d3318ca022dcda540a86b9f60bb314c78998b.zip |
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
7 files changed, 324 insertions, 1 deletions
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; /** @@ -61,6 +62,28 @@ public class IccUtils { } /** + * 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 */ public static String 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<PlmnActRecord> CREATOR = + new Parcelable.Creator<PlmnActRecord>() { + @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 @@ -1916,6 +2013,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 */ private boolean isCphsMailboxEnabled() { @@ -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: |