in com/android/internal/telephony/uicc/SIMRecords.java [631:1361]
public void handleMessage(Message msg) {
AsyncResult ar;
AdnRecord adn;
byte data[];
boolean isRecordLoadResponse = false;
if (mDestroyed.get()) {
loge("Received message " + msg + "[" + msg.what + "] " +
" while being destroyed. Ignoring.");
return;
}
try {
switch (msg.what) {
case EVENT_APP_READY:
onReady();
break;
case EVENT_APP_LOCKED:
case EVENT_APP_NETWORK_LOCKED:
onLocked(msg.what);
break;
/* IO events */
case EVENT_GET_IMSI_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
loge("Exception querying IMSI, Exception:" + ar.exception);
break;
}
mImsi = (String) ar.result;
// IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
// than 15 (and usually 15).
if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
loge("invalid IMSI " + mImsi);
mImsi = null;
}
log("IMSI: mMncLength=" + mMncLength);
if (mImsi != null && mImsi.length() >= 6) {
log("IMSI: " + mImsi.substring(0, 6)
+ Rlog.pii(LOG_TAG, mImsi.substring(6)));
}
String imsi = getIMSI();
if (((mMncLength == UNKNOWN) || (mMncLength == 2))
&& ((imsi != null) && (imsi.length() >= 6))) {
String mccmncCode = imsi.substring(0, 6);
for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
if (mccmnc.equals(mccmncCode)) {
mMncLength = 3;
log("IMSI: setting1 mMncLength=" + mMncLength);
break;
}
}
}
if (mMncLength == UNKNOWN) {
// the SIM has told us all it knows, but it didn't know the mnc length.
// guess using the mcc
try {
int mcc = Integer.parseInt(imsi.substring(0, 3));
mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
log("setting2 mMncLength=" + mMncLength);
} catch (NumberFormatException e) {
mMncLength = UNKNOWN;
loge("Corrupt IMSI! setting3 mMncLength=" + mMncLength);
}
}
if (mMncLength != UNKNOWN && mMncLength != UNINITIALIZED
&& imsi.length() >= 3 + mMncLength) {
log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
// finally have both the imsi and the mncLength and
// can parse the imsi properly
MccTable.updateMccMncConfiguration(mContext,
imsi.substring(0, 3 + mMncLength), false);
}
mImsiReadyRegistrants.notifyRegistrants();
break;
case EVENT_GET_MBI_DONE:
boolean isValidMbdn;
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
isValidMbdn = false;
if (ar.exception == null) {
// Refer TS 51.011 Section 10.3.44 for content details
log("EF_MBI: " + IccUtils.bytesToHexString(data));
// Voice mail record number stored first
mMailboxIndex = data[0] & 0xff;
// check if dailing numbe id valid
if (mMailboxIndex != 0 && mMailboxIndex != 0xff) {
log("Got valid mailbox number for MBDN");
isValidMbdn = true;
}
}
// one more record to load
mRecordsToLoad += 1;
if (isValidMbdn) {
// Note: MBDN was not included in NUM_OF_SIM_RECORDS_LOADED
new AdnRecordLoader(mFh).loadFromEF(EF_MBDN, EF_EXT6,
mMailboxIndex, obtainMessage(EVENT_GET_MBDN_DONE));
} else {
// If this EF not present, try mailbox as in CPHS standard
// CPHS (CPHS4_2.WW6) is a european standard.
new AdnRecordLoader(mFh).loadFromEF(EF_MAILBOX_CPHS,
EF_EXT1, 1,
obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
}
break;
case EVENT_GET_CPHS_MAILBOX_DONE:
case EVENT_GET_MBDN_DONE:
//Resetting the voice mail number and voice mail tag to null
//as these should be updated from the data read from EF_MBDN.
//If they are not reset, incase of invalid data/exception these
//variables are retaining their previous values and are
//causing invalid voice mailbox info display to user.
mVoiceMailNum = null;
mVoiceMailTag = null;
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
log("Invalid or missing EF"
+ ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE)
? "[MAILBOX]" : "[MBDN]"));
// Bug #645770 fall back to CPHS
// FIXME should use SST to decide
if (msg.what == EVENT_GET_MBDN_DONE) {
//load CPHS on fail...
// FIXME right now, only load line1's CPHS voice mail entry
mRecordsToLoad += 1;
new AdnRecordLoader(mFh).loadFromEF(
EF_MAILBOX_CPHS, EF_EXT1, 1,
obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
}
break;
}
adn = (AdnRecord) ar.result;
log("VM: " + adn
+ ((msg.what == EVENT_GET_CPHS_MAILBOX_DONE)
? " EF[MAILBOX]" : " EF[MBDN]"));
if (adn.isEmpty() && msg.what == EVENT_GET_MBDN_DONE) {
// Bug #645770 fall back to CPHS
// FIXME should use SST to decide
// FIXME right now, only load line1's CPHS voice mail entry
mRecordsToLoad += 1;
new AdnRecordLoader(mFh).loadFromEF(
EF_MAILBOX_CPHS, EF_EXT1, 1,
obtainMessage(EVENT_GET_CPHS_MAILBOX_DONE));
break;
}
mVoiceMailNum = adn.getNumber();
mVoiceMailTag = adn.getAlphaTag();
break;
case EVENT_GET_MSISDN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
log("Invalid or missing EF[MSISDN]");
break;
}
adn = (AdnRecord) ar.result;
mMsisdn = adn.getNumber();
mMsisdnTag = adn.getAlphaTag();
log("MSISDN: " + /*mMsisdn*/ Rlog.pii(LOG_TAG, mMsisdn));
break;
case EVENT_SET_MSISDN_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
mMsisdn = mNewMsisdn;
mMsisdnTag = mNewMsisdnTag;
log("Success to update EF[MSISDN]");
}
if (ar.userObj != null) {
AsyncResult.forMessage(((Message) ar.userObj)).exception = ar.exception;
((Message) ar.userObj).sendToTarget();
}
break;
case EVENT_GET_MWIS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (DBG) log("EF_MWIS : " + IccUtils.bytesToHexString(data));
if (ar.exception != null) {
if (DBG) log("EVENT_GET_MWIS_DONE exception = " + ar.exception);
break;
}
if ((data[0] & 0xff) == 0xff) {
if (DBG) log("SIMRecords: Uninitialized record MWIS");
break;
}
mEfMWIS = data;
break;
case EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (DBG) log("EF_CPHS_MWI: " + IccUtils.bytesToHexString(data));
if (ar.exception != null) {
if (DBG) {
log("EVENT_GET_VOICE_MAIL_INDICATOR_CPHS_DONE exception = "
+ ar.exception);
}
break;
}
mEfCPHS_MWI = data;
break;
case EVENT_GET_ICCID_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
mIccId = IccUtils.bcdToString(data, 0, data.length);
mFullIccId = IccUtils.bchToString(data, 0, data.length);
log("iccid: " + SubscriptionInfo.givePrintableIccid(mFullIccId));
break;
case EVENT_GET_AD_DONE:
try {
isRecordLoadResponse = true;
if (mCarrierTestOverride.isInTestMode() && getIMSI() != null) {
imsi = getIMSI();
try {
int mcc = Integer.parseInt(imsi.substring(0, 3));
mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
log("[TestMode] mMncLength=" + mMncLength);
} catch (NumberFormatException e) {
mMncLength = UNKNOWN;
loge("[TestMode] Corrupt IMSI! mMncLength=" + mMncLength);
}
} else {
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
log("EF_AD: " + IccUtils.bytesToHexString(data));
if (data.length < 3) {
log("Corrupt AD data on SIM");
break;
}
if (data.length == 3) {
log("MNC length not present in EF_AD");
break;
}
mMncLength = data[3] & 0xf;
log("setting4 mMncLength=" + mMncLength);
}
if (mMncLength == 0xf) {
mMncLength = UNKNOWN;
log("setting5 mMncLength=" + mMncLength);
} else if (mMncLength != 2 && mMncLength != 3) {
mMncLength = UNINITIALIZED;
log("setting5 mMncLength=" + mMncLength);
}
} finally {
// IMSI could be a value reading from Sim or a fake IMSI if in the test mode
imsi = getIMSI();
if (((mMncLength == UNINITIALIZED) || (mMncLength == UNKNOWN)
|| (mMncLength == 2)) && ((imsi != null)
&& (imsi.length() >= 6))) {
String mccmncCode = imsi.substring(0, 6);
log("mccmncCode=" + mccmncCode);
for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
if (mccmnc.equals(mccmncCode)) {
mMncLength = 3;
log("setting6 mMncLength=" + mMncLength);
break;
}
}
}
if (mMncLength == UNKNOWN || mMncLength == UNINITIALIZED) {
if (imsi != null) {
try {
int mcc = Integer.parseInt(imsi.substring(0, 3));
mMncLength = MccTable.smallestDigitsMccForMnc(mcc);
log("setting7 mMncLength=" + mMncLength);
} catch (NumberFormatException e) {
mMncLength = UNKNOWN;
loge("Corrupt IMSI! setting8 mMncLength=" + mMncLength);
}
} else {
// Indicate we got this info, but it didn't contain the length.
mMncLength = UNKNOWN;
log("MNC length not present in EF_AD setting9 "
+ "mMncLength=" + mMncLength);
}
}
if (imsi != null && mMncLength != UNKNOWN
&& imsi.length() >= 3 + mMncLength) {
// finally have both imsi and the length of the mnc and can parse
// the imsi properly
log("update mccmnc=" + imsi.substring(0, 3 + mMncLength));
MccTable.updateMccMncConfiguration(mContext,
imsi.substring(0, 3 + mMncLength), false);
}
}
break;
case EVENT_GET_SPN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
getSpnFsm(false, ar);
break;
case EVENT_GET_CFF_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
mEfCff = null;
} else {
log("EF_CFF_CPHS: " + IccUtils.bytesToHexString(data));
mEfCff = data;
}
break;
case EVENT_GET_SPDI_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
parseEfSpdi(data);
break;
case EVENT_UPDATE_DONE:
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
logw("update failed. ", ar.exception);
}
break;
case EVENT_GET_PNN_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
SimTlv tlv = new SimTlv(data, 0, data.length);
for (; tlv.isValidObject(); tlv.nextObject()) {
if (tlv.getTag() == TAG_FULL_NETWORK_NAME) {
mPnnHomeName = IccUtils.networkNameToString(
tlv.getData(), 0, tlv.getData().length);
log("PNN: " + mPnnHomeName);
break;
}
}
break;
case EVENT_GET_ALL_SMS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
break;
}
handleSmses((ArrayList<byte []>) ar.result);
break;
case EVENT_MARK_SMS_READ_DONE:
Rlog.i("ENF", "marked read: sms " + msg.arg1);
break;
case EVENT_SMS_ON_SIM:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
Integer index = (Integer) ar.result;
if (ar.exception != null || index == null) {
loge("Error on SMS_ON_SIM with exp "
+ ar.exception + " index " + index);
} else {
log("READ EF_SMS RECORD index=" + index);
mFh.loadEFLinearFixed(EF_SMS, index, obtainMessage(EVENT_GET_SMS_DONE));
}
break;
case EVENT_GET_SMS_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
handleSms((byte[]) ar.result);
} else {
loge("Error on GET_SMS with exp " + ar.exception);
}
break;
case EVENT_GET_SST_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
break;
}
mUsimServiceTable = new UsimServiceTable(data);
if (DBG) log("SST: " + mUsimServiceTable);
break;
case EVENT_GET_INFO_CPHS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
break;
}
mCphsInfo = (byte[]) ar.result;
if (DBG) log("iCPHS: " + IccUtils.bytesToHexString(mCphsInfo));
break;
case EVENT_SET_MBDN_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (DBG) log("EVENT_SET_MBDN_DONE ex:" + ar.exception);
if (ar.exception == null) {
mVoiceMailNum = mNewVoiceMailNum;
mVoiceMailTag = mNewVoiceMailTag;
}
if (isCphsMailboxEnabled()) {
adn = new AdnRecord(mVoiceMailTag, mVoiceMailNum);
Message onCphsCompleted = (Message) ar.userObj;
/* write to cphs mailbox whenever it is available but
* we only need notify caller once if both updating are
* successful.
*
* so if set_mbdn successful, notify caller here and set
* onCphsCompleted to null
*/
if (ar.exception == null && ar.userObj != null) {
AsyncResult.forMessage(((Message) ar.userObj)).exception = null;
((Message) ar.userObj).sendToTarget();
if (DBG) log("Callback with MBDN successful.");
onCphsCompleted = null;
}
new AdnRecordLoader(mFh)
.updateEF(adn, EF_MAILBOX_CPHS, EF_EXT1, 1, null,
obtainMessage(EVENT_SET_CPHS_MAILBOX_DONE,
onCphsCompleted));
} else {
if (ar.userObj != null) {
CarrierConfigManager configLoader = (CarrierConfigManager)
mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE);
if (ar.exception != null && configLoader != null
&& configLoader.getConfig().getBoolean(
CarrierConfigManager.KEY_EDITABLE_VOICEMAIL_NUMBER_BOOL)) {
// GsmCdmaPhone will store vm number on device
// when IccVmNotSupportedException occurred
AsyncResult.forMessage(((Message) ar.userObj)).exception =
new IccVmNotSupportedException(
"Update SIM voice mailbox error");
} else {
AsyncResult.forMessage(((Message) ar.userObj))
.exception = ar.exception;
}
((Message) ar.userObj).sendToTarget();
}
}
break;
case EVENT_SET_CPHS_MAILBOX_DONE:
isRecordLoadResponse = false;
ar = (AsyncResult) msg.obj;
if (ar.exception == null) {
mVoiceMailNum = mNewVoiceMailNum;
mVoiceMailTag = mNewVoiceMailTag;
} else {
if (DBG) log("Set CPHS MailBox with exception: " + ar.exception);
}
if (ar.userObj != null) {
if (DBG) log("Callback with CPHS MB successful.");
AsyncResult.forMessage(((Message) ar.userObj)).exception
= ar.exception;
((Message) ar.userObj).sendToTarget();
}
break;
case EVENT_GET_CFIS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
mEfCfis = null;
} else {
log("EF_CFIS: " + IccUtils.bytesToHexString(data));
mEfCfis = data;
}
break;
case EVENT_GET_CSP_CPHS_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
if (ar.exception != null) {
loge("Exception in fetching EF_CSP data " + ar.exception);
break;
}
data = (byte[]) ar.result;
log("EF_CSP: " + IccUtils.bytesToHexString(data));
handleEfCspData(data);
break;
case EVENT_GET_GID1_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
loge("Exception in get GID1 " + ar.exception);
mGid1 = null;
break;
}
mGid1 = IccUtils.bytesToHexString(data);
log("GID1: " + mGid1);
break;
case EVENT_GET_GID2_DONE:
isRecordLoadResponse = true;
ar = (AsyncResult) msg.obj;
data = (byte[]) ar.result;
if (ar.exception != null) {
loge("Exception in get GID2 " + ar.exception);
mGid2 = null;
break;
}
mGid2 = IccUtils.bytesToHexString(data);
log("GID2: " + mGid2);
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");
}
if (msg.arg1 == HANDLER_ACTION_SEND_RESPONSE) {
if (VDBG) logv("getForbiddenPlmns(): send async response");
isRecordLoadResponse = false;
Message response = retrievePendingResponseMessage(msg.arg2);
if (response != null) {
AsyncResult.forMessage(
response, Arrays.copyOf(mFplmns, mFplmns.length), null);
response.sendToTarget();
} else {
loge("Failed to retrieve a response message for FPLMN");
break;
}
}
break;
default:
super.handleMessage(msg); // IccRecords handles generic record load responses
}
} catch (RuntimeException exc) {
// I don't want these exceptions to be fatal
logw("Exception parsing SIM record", exc);
} finally {
// Count up record load responses even if they are fails
if (isRecordLoadResponse) {
onRecordLoaded();
}
}
}