diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java index 06040d623b6758721e8150565e106a033fbba52f..05ba09cd52f31971d600e38c1ffe6ff4e72bd636 100644 --- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java +++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java @@ -2890,6 +2890,11 @@ public class GsmCdmaPhone extends Phone { } } + @Override + public SIMRecords getSIMRecords() { + return mSimRecords; + } + private void processIccRecordEvents(int eventCode) { switch (eventCode) { case IccRecords.EVENT_CFI: diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java index eddf121ae064d09fec955b7d9658e0082db1be3c..c830316886c9324f8d632167fa9382fc7bcc1b95 100644 --- a/src/java/com/android/internal/telephony/Phone.java +++ b/src/java/com/android/internal/telephony/Phone.java @@ -82,6 +82,7 @@ import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType; import com.android.internal.telephony.uicc.IccFileHandler; import com.android.internal.telephony.uicc.IccRecords; import com.android.internal.telephony.uicc.IsimRecords; +import com.android.internal.telephony.uicc.SIMRecords; import com.android.internal.telephony.uicc.UiccCard; import com.android.internal.telephony.uicc.UiccCardApplication; import com.android.internal.telephony.uicc.UiccController; @@ -4109,6 +4110,10 @@ public abstract class Phone extends Handler implements PhoneInternalInterface { return RIL.RADIO_HAL_VERSION_UNKNOWN; } + public SIMRecords getSIMRecords() { + return null; + } + public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Phone: subId=" + getSubId()); pw.println(" mPhoneId=" + mPhoneId); diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java index 6a30c476ab4a72ca3f65eb212591f3428b863d23..4e45a928d95f7bfd12fa54499fc74780dea0f835 100644 --- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java +++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java @@ -111,6 +111,8 @@ import com.android.internal.telephony.dataconnection.DataConnectionReasons.DataD import com.android.internal.telephony.dataconnection.DataEnabledSettings.DataEnabledChangedReason; import com.android.internal.telephony.metrics.TelephonyMetrics; import com.android.internal.telephony.uicc.IccRecords; +import com.android.internal.telephony.uicc.RuimRecords; +import com.android.internal.telephony.uicc.SIMRecords; import com.android.internal.telephony.uicc.UiccController; import com.android.internal.util.ArrayUtils; import com.android.internal.util.AsyncChannel; @@ -232,6 +234,7 @@ public class DcTracker extends Handler { private final TelephonyManager mTelephonyManager; private final AlarmManager mAlarmManager; + private SIMRecords mSimRecords; /* Currently requested APN type (TODO: This should probably be a parameter not a member) */ private int mRequestedApnType = ApnSetting.TYPE_DEFAULT; @@ -250,6 +253,8 @@ public class DcTracker extends Handler { // Default sent packets without ack which triggers initial recovery steps private static final int NUMBER_SENT_PACKETS_OF_HANG = 10; + private static final int EVENT_ESSENTIAL_SIM_RECORDS_LOADED = 100; + // Default for the data stall alarm while non-aggressive stall detection private static final int DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS_DEFAULT = 1000 * 60 * 6; // Default for the data stall alarm for aggressive stall detection @@ -1362,7 +1367,8 @@ public class DcTracker extends Handler { radioStateFromCarrier = true; } - boolean recordsLoaded = mIccRecords.get() != null && mIccRecords.get().getRecordsLoaded(); + boolean recordsLoaded = mIccRecords.get() != null + && mIccRecords.get().getEssentialRecordsLoaded(); boolean defaultDataSelected = SubscriptionManager.isValidSubscriptionId( SubscriptionManager.getDefaultDataSubscriptionId()); @@ -3550,6 +3556,17 @@ public class DcTracker extends Handler { return null; } + void onRecordsLoaded() { + // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on + // onSubscriptionsChanged() when a valid subId is available. + int subId = mPhone.getSubId(); + if (mSubscriptionManager.isActiveSubId(subId)) { + onRecordsLoadedOrSubIdChanged(); + } else { + log("Ignoring EVENT_ESSENTIAL_SIM_RECORDS_LOADED as subId is not valid: " + subId); + } + } + @Override public void handleMessage (Message msg) { if (VDBG) log("handleMessage msg=" + msg); @@ -3561,13 +3578,21 @@ public class DcTracker extends Handler { int requestType; switch (msg.what) { case DctConstants.EVENT_RECORDS_LOADED: - // If onRecordsLoadedOrSubIdChanged() is not called here, it should be called on - // onSubscriptionsChanged() when a valid subId is available. - int subId = mPhone.getSubId(); - if (mSubscriptionManager.isActiveSubId(subId)) { - onRecordsLoadedOrSubIdChanged(); + mSimRecords = mPhone.getSIMRecords(); + if ((mIccRecords.get() instanceof RuimRecords) && (mSimRecords != null)) { + mSimRecords.registerForEssentialRecordsLoaded( + this, EVENT_ESSENTIAL_SIM_RECORDS_LOADED, null); } else { - log("Ignoring EVENT_RECORDS_LOADED as subId is not valid: " + subId); + onRecordsLoaded(); + } + break; + + case EVENT_ESSENTIAL_SIM_RECORDS_LOADED: + if (DBG) log("EVENT_ESSENTIAL_SIM_RECORDS_LOADED"); + onRecordsLoaded(); + if (mSimRecords != null) { + mSimRecords.unregisterForEssentialRecordsLoaded(this); + mSimRecords = null; } break; @@ -3983,7 +4008,7 @@ public class DcTracker extends Handler { if (mSubscriptionManager.isActiveSubId(mPhone.getSubId())) { log("New records found."); mIccRecords.set(newIccRecords); - newIccRecords.registerForRecordsLoaded( + newIccRecords.registerForEssentialRecordsLoaded( this, DctConstants.EVENT_RECORDS_LOADED, null); } } else { diff --git a/src/java/com/android/internal/telephony/uicc/IccRecords.java b/src/java/com/android/internal/telephony/uicc/IccRecords.java index 7944f6f4d15e601873f072b75474f18160c932c5..7d432aef0b6f4d93d21ea965d2ea69de0233ed2f 100644 --- a/src/java/com/android/internal/telephony/uicc/IccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IccRecords.java @@ -92,6 +92,7 @@ public abstract class IccRecords extends Handler implements IccConstants { protected TelephonyManager mTelephonyManager; protected RegistrantList mRecordsLoadedRegistrants = new RegistrantList(); + protected RegistrantList mEssentialRecordsLoadedRegistrants = new RegistrantList(); protected RegistrantList mLockedRecordsLoadedRegistrants = new RegistrantList(); protected RegistrantList mNetworkLockedRecordsLoadedRegistrants = new RegistrantList(); protected RegistrantList mImsiReadyRegistrants = new RegistrantList(); @@ -102,6 +103,12 @@ public abstract class IccRecords extends Handler implements IccConstants { protected RegistrantList mSpnUpdatedRegistrants = new RegistrantList(); protected RegistrantList mRecordsOverrideRegistrants = new RegistrantList(); + @UnsupportedAppUsage + protected boolean mEssentialRecordsListenerNotified; + + @UnsupportedAppUsage + protected int mEssentialRecordsToLoad; // number of pending essential records load requests + @UnsupportedAppUsage protected int mRecordsToLoad; // number of pending load requests @@ -232,6 +239,7 @@ public abstract class IccRecords extends Handler implements IccConstants { + " mCi=" + mCi + " mFh=" + mFh + " mParentApp=" + mParentApp + + " mEssentialRecordsToLoad=" + mEssentialRecordsToLoad + " recordsToLoad=" + mRecordsToLoad + " adnCache=" + mAdnCache + " recordsRequested=" + mRecordsRequested @@ -370,6 +378,20 @@ public abstract class IccRecords extends Handler implements IccConstants { return mFullIccId; } + @UnsupportedAppUsage + public void registerForEssentialRecordsLoaded(Handler h, int what, Object obj) { + if (mDestroyed.get()) { + return; + } + + Registrant r = new Registrant(h, what, obj); + mEssentialRecordsLoadedRegistrants.add(r); + + if (getEssentialRecordsLoaded()) { + r.notifyRegistrant(new AsyncResult(null, null, null)); + } + } + @UnsupportedAppUsage public void registerForRecordsLoaded(Handler h, int what, Object obj) { if (mDestroyed.get()) { @@ -383,6 +405,12 @@ public abstract class IccRecords extends Handler implements IccConstants { r.notifyRegistrant(new AsyncResult(null, null, null)); } } + + @UnsupportedAppUsage + public void unregisterForEssentialRecordsLoaded(Handler h) { + mEssentialRecordsLoadedRegistrants.remove(h); + } + @UnsupportedAppUsage public void unregisterForRecordsLoaded(Handler h) { mRecordsLoadedRegistrants.remove(h); @@ -771,6 +799,11 @@ public abstract class IccRecords extends Handler implements IccConstants { */ public abstract void onRefresh(boolean fileChanged, int[] fileList); + @UnsupportedAppUsage + public boolean getEssentialRecordsLoaded() { + return mEssentialRecordsToLoad == 0 && mRecordsRequested; + } + @UnsupportedAppUsage public boolean getRecordsLoaded() { return mRecordsToLoad == 0 && mRecordsRequested; @@ -919,6 +952,8 @@ public abstract class IccRecords extends Handler implements IccConstants { protected abstract void onRecordLoaded(); + protected abstract void onAllEssentialRecordsLoaded(); + protected abstract void onAllRecordsLoaded(); /** @@ -1187,6 +1222,12 @@ public abstract class IccRecords extends Handler implements IccConstants { pw.println(" mCi=" + mCi); pw.println(" mFh=" + mFh); pw.println(" mParentApp=" + mParentApp); + pw.println(" mEssentialRecordsLoadedRegistrants: size=" + + mEssentialRecordsLoadedRegistrants.size()); + for (int i = 0; i < mEssentialRecordsLoadedRegistrants.size(); i++) { + pw.println(" mEssentialRecordsLoadedRegistrants[" + i + "]=" + + ((Registrant)mEssentialRecordsLoadedRegistrants.get(i)).getHandler()); + } pw.println(" recordsLoadedRegistrants: size=" + mRecordsLoadedRegistrants.size()); for (int i = 0; i < mRecordsLoadedRegistrants.size(); i++) { pw.println(" recordsLoadedRegistrants[" + i + "]=" @@ -1227,6 +1268,7 @@ public abstract class IccRecords extends Handler implements IccConstants { } pw.println(" mRecordsRequested=" + mRecordsRequested); pw.println(" mLockedRecordsReqReason=" + mLockedRecordsReqReason); + pw.println(" mEssentialRecordsToLoad=" + mEssentialRecordsToLoad); pw.println(" mRecordsToLoad=" + mRecordsToLoad); pw.println(" mRdnCache=" + mAdnCache); diff --git a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java index f75849dcc364bd9b825c2dbc92332a82fae13704..b5b7b45e2e1031cc1320cb7695e189ce11616665 100644 --- a/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java +++ b/src/java/com/android/internal/telephony/uicc/IsimUiccRecords.java @@ -154,9 +154,16 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { } } + private void fetchEssentialIsimRecords() { + //NOP: No essential ISim records identified. + } + @UnsupportedAppUsage protected void fetchIsimRecords() { mRecordsRequested = true; + if (DBG) log("fetchIsimRecords " + mRecordsToLoad); + + fetchEssentialIsimRecords(); mFh.loadEFTransparent(EF_IMPI, obtainMessage( IccRecords.EVENT_GET_ICC_RECORD_DONE, new EfIsimImpiLoaded())); @@ -289,13 +296,18 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { mRecordsToLoad -= 1; if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); + if (getEssentialRecordsLoaded() && !mEssentialRecordsListenerNotified) { + onAllEssentialRecordsLoaded(); + } + if (getRecordsLoaded()) { onAllRecordsLoaded(); } else if (getLockedRecordsLoaded() || getNetworkLockedRecordsLoaded()) { onLockedAllRecordsLoaded(); - } else if (mRecordsToLoad < 0) { + } else if (mRecordsToLoad < 0 || mEssentialRecordsToLoad < 0) { loge("recordsToLoad <0, programmer error suspected"); mRecordsToLoad = 0; + mEssentialRecordsToLoad = 0; } } @@ -312,9 +324,16 @@ public class IsimUiccRecords extends IccRecords implements IsimRecords { } } + @Override + protected void onAllEssentialRecordsLoaded() { + if (DBG) log("Essential record load complete"); + mEssentialRecordsListenerNotified = true; + mEssentialRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); + } + @Override protected void onAllRecordsLoaded() { - if (DBG) log("record load complete"); + if (DBG) log("record load complete"); mLoaded.set(true); mRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); } diff --git a/src/java/com/android/internal/telephony/uicc/RuimRecords.java b/src/java/com/android/internal/telephony/uicc/RuimRecords.java index ff4aad8fe70638fdbb585cf330448602bf793f8d..c69d7f4d8a895519657a054c43452f8b398e034a 100644 --- a/src/java/com/android/internal/telephony/uicc/RuimRecords.java +++ b/src/java/com/android/internal/telephony/uicc/RuimRecords.java @@ -30,6 +30,7 @@ import android.telephony.SubscriptionManager; import android.text.TextUtils; import android.util.Log; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.CommandsInterface; import com.android.internal.telephony.GsmAlphabet; import com.android.internal.telephony.MccTable; @@ -208,16 +209,6 @@ public class RuimRecords extends IccRecords { } } - @UnsupportedAppUsage - private int adjstMinDigits (int digits) { - // Per C.S0005 section 2.3.1. - digits += 111; - digits = (digits % 10 == 0)?(digits - 10):digits; - digits = ((digits / 10) % 10 == 0)?(digits - 100):digits; - digits = ((digits / 100) % 10 == 0)?(digits - 1000):digits; - return digits; - } - /** * Returns the 5 or 6 digit MCC/MNC of the operator that * provided the RUIM card. Returns null of RUIM is not yet ready @@ -376,7 +367,8 @@ public class RuimRecords extends IccRecords { } } - private class EfCsimImsimLoaded implements IccRecordLoaded { + @VisibleForTesting + public class EfCsimImsimLoaded implements IccRecordLoaded { @Override public String getEfName() { return "EF_CSIM_IMSIM"; @@ -384,33 +376,77 @@ public class RuimRecords extends IccRecords { @Override public void onRecordLoaded(AsyncResult ar) { + mEssentialRecordsToLoad -= 1; byte[] data = (byte[]) ar.result; - if (VDBG) log("CSIM_IMSIM=" + IccUtils.bytesToHexString(data)); + if (data == null || data.length < 10) { + if (DBG) log("Invalid IMSI from EF_CSIM_IMSIM"); + return; + } + if (DBG) Rlog.pii(LOG_TAG, IccUtils.bytesToHexString(data)); // C.S0065 section 5.2.2 for IMSI_M encoding // C.S0005 section 2.3.1 for MIN encoding in IMSI_M. boolean provisioned = ((data[7] & 0x80) == 0x80); if (provisioned) { - int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]); - int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6; - int digit7 = 0x0F & (data[4] >> 2); - if (digit7 > 0x09) digit7 = 0; - int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]); - first3digits = adjstMinDigits(first3digits); - second3digits = adjstMinDigits(second3digits); - last3digits = adjstMinDigits(last3digits); - - StringBuilder builder = new StringBuilder(); - builder.append(String.format(Locale.US, "%03d", first3digits)); - builder.append(String.format(Locale.US, "%03d", second3digits)); - builder.append(String.format(Locale.US, "%d", digit7)); - builder.append(String.format(Locale.US, "%03d", last3digits)); - mMin = builder.toString(); + final String imsi = decodeImsi(data); + if (TextUtils.isEmpty(mImsi)) { + mImsi = imsi; + if (DBG) log("IMSI=" + Rlog.pii(LOG_TAG, mImsi)); + } + if (null != imsi) { + mMin = imsi.substring(5, 15); + } if (DBG) log("min present=" + Rlog.pii(LOG_TAG, mMin)); } else { if (DBG) log("min not present"); } } + + private int decodeImsiDigits(int digits, int length) { + // Per C.S0005 section 2.3.1. + for (int i = 0, denominator = 1; i < length; i++) { + digits += denominator; + if ((digits / denominator) % 10 == 0) { + digits = digits - (10 * denominator); + } + denominator *= 10; + } + return digits; + } + + /** + * Decode utility to decode IMSI from data read from EF_IMSIM + * Please refer to + * C.S0065 section 5.2.2 for IMSI_M encoding + * C.S0005 section 2.3.1 for MIN encoding in IMSI_M. + */ + private String decodeImsi(byte[] data) { + // Retrieve the MCC and digits 11 and 12 + int mcc_data = ((0x03 & data[9]) << 8) | (0xFF & data[8]); + int mcc = decodeImsiDigits(mcc_data, 3); + int digits_11_12_data = data[6] & 0x7f; + int digits_11_12 = decodeImsiDigits(digits_11_12_data, 2); + + // Retrieve 10 MIN digits + int first3digits = ((0x03 & data[2]) << 8) + (0xFF & data[1]); + int second3digits = (((0xFF & data[5]) << 8) | (0xFF & data[4])) >> 6; + int digit7 = 0x0F & (data[4] >> 2); + if (digit7 > 0x09) digit7 = 0; + int last3digits = ((0x03 & data[4]) << 8) | (0xFF & data[3]); + + first3digits = decodeImsiDigits(first3digits, 3); + second3digits = decodeImsiDigits(second3digits, 3); + last3digits = decodeImsiDigits(last3digits, 3); + + StringBuilder builder = new StringBuilder(); + builder.append(String.format(Locale.US, "%03d", mcc)); + builder.append(String.format(Locale.US, "%02d", digits_11_12)); + builder.append(String.format(Locale.US, "%03d", first3digits)); + builder.append(String.format(Locale.US, "%03d", second3digits)); + builder.append(String.format(Locale.US, "%d", digit7)); + builder.append(String.format(Locale.US, "%03d", last3digits)); + return builder.toString(); + } } private class EfCsimCdmaHomeLoaded implements IccRecordLoaded { @@ -629,6 +665,7 @@ public class RuimRecords extends IccRecords { /* IO events */ case EVENT_GET_IMSI_DONE: isRecordLoadResponse = true; + mEssentialRecordsToLoad -= 1; ar = (AsyncResult)msg.obj; if (ar.exception != null) { @@ -680,6 +717,7 @@ public class RuimRecords extends IccRecords { case EVENT_GET_ICCID_DONE: isRecordLoadResponse = true; + mEssentialRecordsToLoad -= 1; ar = (AsyncResult)msg.obj; data = (byte[])ar.result; @@ -758,13 +796,18 @@ public class RuimRecords extends IccRecords { mRecordsToLoad -= 1; if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); + if (getEssentialRecordsLoaded() && !mEssentialRecordsListenerNotified) { + onAllEssentialRecordsLoaded(); + } + if (getRecordsLoaded()) { onAllRecordsLoaded(); } else if (getLockedRecordsLoaded() || getNetworkLockedRecordsLoaded()) { onLockedAllRecordsLoaded(); - } else if (mRecordsToLoad < 0) { + } else if (mRecordsToLoad < 0 || mEssentialRecordsToLoad < 0) { loge("recordsToLoad <0, programmer error suspected"); mRecordsToLoad = 0; + mEssentialRecordsToLoad = 0; } } @@ -781,8 +824,8 @@ public class RuimRecords extends IccRecords { } @Override - protected void onAllRecordsLoaded() { - if (DBG) log("record load complete"); + protected void onAllEssentialRecordsLoaded() { + if (DBG) log("Essential record load complete"); // Further records that can be inserted are Operator/OEM dependent @@ -790,26 +833,34 @@ public class RuimRecords extends IccRecords { if (false) { String operator = getRUIMOperatorNumeric(); if (!TextUtils.isEmpty(operator)) { - log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + + log("onAllEssentialRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + operator + "'"); log("update icc_operator_numeric=" + operator); mTelephonyManager.setSimOperatorNumericForPhone( mParentApp.getPhoneId(), operator); } else { - log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); + log("onAllEssentialRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); } String imsi = getIMSI(); if (!TextUtils.isEmpty(imsi)) { - log("onAllRecordsLoaded set mcc imsi=" + (VDBG ? ("=" + imsi) : "")); + log("onAllEssentialRecordsLoaded set mcc imsi=" + (VDBG ? ("=" + imsi) : "")); mTelephonyManager.setSimCountryIsoForPhone(mParentApp.getPhoneId(), MccTable.countryCodeForMcc(imsi.substring(0, 3))); } else { - log("onAllRecordsLoaded empty imsi skipping setting mcc"); + log("onAllEssentialRecordsLoaded empty imsi skipping setting mcc"); } } + mEssentialRecordsListenerNotified = true; + mEssentialRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); + } + + @Override + protected void onAllRecordsLoaded() { + if (DBG) log("record load complete"); + Resources resource = Resources.getSystem(); if (resource.getBoolean(com.android.internal.R.bool.config_use_sim_language_file)) { setSimLanguage(mEFli, mEFpl); @@ -846,18 +897,37 @@ public class RuimRecords extends IccRecords { mRecordsToLoad++; } - @UnsupportedAppUsage - private void fetchRuimRecords() { - mRecordsRequested = true; - - if (DBG) log("fetchRuimRecords " + mRecordsToLoad); + private void fetchEssentialRuimRecords() { + if (DBG) log("fetchEssentialRuimRecords " + mRecordsToLoad); - mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); - mRecordsToLoad++; + if (!TextUtils.isEmpty(mParentApp.getAid()) + || mParentApp.getUiccProfile().getNumApplications() <= 1) { + mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); + mRecordsToLoad++; + mEssentialRecordsToLoad++; + } mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); mRecordsToLoad++; + mEssentialRecordsToLoad++; + + mFh.loadEFTransparent(EF_CSIM_IMSIM, + obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimImsimLoaded())); + mRecordsToLoad++; + mEssentialRecordsToLoad++; + + if (DBG) log("fetchEssentialRuimRecords " + mRecordsToLoad + + " requested: " + mRecordsRequested); + } + + @UnsupportedAppUsage + private void fetchRuimRecords() { + mRecordsRequested = true; + + fetchEssentialRuimRecords(); + + if (DBG) log("fetchRuimRecords " + mRecordsToLoad); mFh.loadEFTransparent(EF_PL, obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfPlLoaded())); @@ -875,10 +945,6 @@ public class RuimRecords extends IccRecords { obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimMdnLoaded())); mRecordsToLoad++; - mFh.loadEFTransparent(EF_CSIM_IMSIM, - obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimImsimLoaded())); - mRecordsToLoad++; - mFh.loadEFLinearFixedAll(EF_CSIM_CDMAHOME, obtainMessage(EVENT_GET_ICC_RECORD_DONE, new EfCsimCdmaHomeLoaded())); mRecordsToLoad++; diff --git a/src/java/com/android/internal/telephony/uicc/SIMRecords.java b/src/java/com/android/internal/telephony/uicc/SIMRecords.java index 4f5f37068e08dcfa9405fc59b28a75365d63040e..a1577095551327c8155cd55b7525a11f7477c4a1 100755 --- a/src/java/com/android/internal/telephony/uicc/SIMRecords.java +++ b/src/java/com/android/internal/telephony/uicc/SIMRecords.java @@ -639,6 +639,7 @@ public class SIMRecords extends IccRecords { /* IO events */ case EVENT_GET_IMSI_DONE: isRecordLoadResponse = true; + mEssentialRecordsToLoad -= 1; ar = (AsyncResult) msg.obj; if (ar.exception != null) { @@ -745,6 +746,7 @@ public class SIMRecords extends IccRecords { case EVENT_GET_MSISDN_DONE: isRecordLoadResponse = true; + mEssentialRecordsToLoad -= 1; ar = (AsyncResult) msg.obj; @@ -819,6 +821,7 @@ public class SIMRecords extends IccRecords { case EVENT_GET_ICCID_DONE: isRecordLoadResponse = true; + mEssentialRecordsToLoad -= 1; ar = (AsyncResult) msg.obj; data = (byte[]) ar.result; @@ -1111,6 +1114,7 @@ public class SIMRecords extends IccRecords { case EVENT_GET_GID1_DONE: isRecordLoadResponse = true; + mEssentialRecordsToLoad -= 1; ar = (AsyncResult) msg.obj; data = (byte[]) ar.result; @@ -1129,6 +1133,7 @@ public class SIMRecords extends IccRecords { case EVENT_GET_GID2_DONE: isRecordLoadResponse = true; + mEssentialRecordsToLoad -= 1; ar = (AsyncResult) msg.obj; data = (byte[]) ar.result; @@ -1380,13 +1385,18 @@ public class SIMRecords extends IccRecords { mRecordsToLoad -= 1; if (DBG) log("onRecordLoaded " + mRecordsToLoad + " requested: " + mRecordsRequested); + if (getEssentialRecordsLoaded() && !mEssentialRecordsListenerNotified) { + onAllEssentialRecordsLoaded(); + } + if (getRecordsLoaded()) { onAllRecordsLoaded(); } else if (getLockedRecordsLoaded() || getNetworkLockedRecordsLoaded()) { onLockedAllRecordsLoaded(); - } else if (mRecordsToLoad < 0) { + }else if (mRecordsToLoad < 0 || mEssentialRecordsToLoad < 0) { loge("recordsToLoad <0, programmer error suspected"); mRecordsToLoad = 0; + mEssentialRecordsToLoad = 0; } } @@ -1430,35 +1440,41 @@ public class SIMRecords extends IccRecords { } @Override - protected void onAllRecordsLoaded() { - if (DBG) log("record load complete"); - - setSimLanguageFromEF(); - setVoiceCallForwardingFlagFromSimRecords(); - - // Some fields require more than one SIM record to set + protected void onAllEssentialRecordsLoaded() { + if (DBG) log("Essential record load complete"); String operator = getOperatorNumeric(); if (!TextUtils.isEmpty(operator)) { - log("onAllRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + + log("onAllEssentialRecordsLoaded set 'gsm.sim.operator.numeric' to operator='" + operator + "'"); mTelephonyManager.setSimOperatorNumericForPhone( mParentApp.getPhoneId(), operator); } else { - log("onAllRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); + log("onAllEssentialRecordsLoaded empty 'gsm.sim.operator.numeric' skipping"); } String imsi = getIMSI(); if (!TextUtils.isEmpty(imsi) && imsi.length() >= 3) { - log("onAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + imsi) : "")); + log("onEssentialAllRecordsLoaded set mcc imsi" + (VDBG ? ("=" + imsi) : "")); mTelephonyManager.setSimCountryIsoForPhone( mParentApp.getPhoneId(), MccTable.countryCodeForMcc(imsi.substring(0, 3))); } else { - log("onAllRecordsLoaded empty imsi skipping setting mcc"); + log("onEssentialAllRecordsLoaded empty imsi skipping setting mcc"); } setVoiceMailByCountry(operator); + mEssentialRecordsListenerNotified = true; + mEssentialRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); + } + + @Override + protected void onAllRecordsLoaded() { + if (DBG) log("record load complete"); + + setSimLanguageFromEF(); + setVoiceCallForwardingFlagFromSimRecords(); + mLoaded.set(true); mRecordsLoadedRegistrants.notifyRegistrants(new AsyncResult(null, null, null)); } @@ -1519,23 +1535,43 @@ public class SIMRecords extends IccRecords { mRecordsToLoad++; } - @UnsupportedAppUsage - protected void fetchSimRecords() { - mRecordsRequested = true; - - if (DBG) log("fetchSimRecords " + mRecordsToLoad); + private void fetchEssentialSimRecords() { + if (DBG) log("fetchEssentialSimRecords " + mRecordsToLoad); mCi.getIMSIForApp(mParentApp.getAid(), obtainMessage(EVENT_GET_IMSI_DONE)); mRecordsToLoad++; + mEssentialRecordsToLoad++; mFh.loadEFTransparent(EF_ICCID, obtainMessage(EVENT_GET_ICCID_DONE)); mRecordsToLoad++; + mEssentialRecordsToLoad++; // FIXME should examine EF[MSISDN]'s capability configuration // to determine which is the voice/data/fax line new AdnRecordLoader(mFh).loadFromEF(EF_MSISDN, getExtFromEf(EF_MSISDN), 1, obtainMessage(EVENT_GET_MSISDN_DONE)); mRecordsToLoad++; + mEssentialRecordsToLoad++; + + mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); + mRecordsToLoad++; + mEssentialRecordsToLoad++; + + mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); + mRecordsToLoad++; + mEssentialRecordsToLoad++; + + if (DBG) log("fetchEssentialSimRecords " + mRecordsToLoad + + " requested: " + mRecordsRequested); + } + + @UnsupportedAppUsage + protected void fetchSimRecords() { + mRecordsRequested = true; + + fetchEssentialSimRecords(); + + if (DBG) log("fetchSimRecords " + mRecordsToLoad); // Record number is subscriber profile mFh.loadEFLinearFixed(EF_MBI, 1, obtainMessage(EVENT_GET_MBI_DONE)); @@ -1579,11 +1615,6 @@ public class SIMRecords extends IccRecords { mFh.loadEFTransparent(EF_CSP_CPHS,obtainMessage(EVENT_GET_CSP_CPHS_DONE)); mRecordsToLoad++; - mFh.loadEFTransparent(EF_GID1, obtainMessage(EVENT_GET_GID1_DONE)); - mRecordsToLoad++; - - mFh.loadEFTransparent(EF_GID2, obtainMessage(EVENT_GET_GID2_DONE)); - mRecordsToLoad++; mFh.loadEFTransparent(EF_PLMN_W_ACT, obtainMessage(EVENT_GET_PLMN_W_ACT_DONE)); mRecordsToLoad++; diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java index e34f99d5fff451f1aafa4fd68450dfe7dc91ea19..a1a07c41ba81b22a787fcc70ebff4ec8fa494da8 100644 --- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java +++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java @@ -98,6 +98,7 @@ public class UiccProfile extends IccCard { private int mGsmUmtsSubscriptionAppIndex; private int mCdmaSubscriptionAppIndex; private int mImsSubscriptionAppIndex; + private int mApplicationCount; private UiccCardApplication[] mUiccApplications = new UiccCardApplication[IccCardStatus.CARD_MAX_APPS]; private Context mContext; @@ -955,6 +956,7 @@ public class UiccProfile extends IccCard { mGsmUmtsSubscriptionAppIndex = ics.mGsmUmtsSubscriptionAppIndex; mCdmaSubscriptionAppIndex = ics.mCdmaSubscriptionAppIndex; mImsSubscriptionAppIndex = ics.mImsSubscriptionAppIndex; + mApplicationCount = ics.mApplications.length; mContext = c; mCi = ci; mTelephonyManager = (TelephonyManager) mContext.getSystemService( @@ -1520,13 +1522,9 @@ public class UiccProfile extends IccCard { * Returns number of applications on this card */ public int getNumApplications() { - int count = 0; - for (UiccCardApplication a : mUiccApplications) { - if (a != null) { - count++; - } + synchronized (mLock) { + return mApplicationCount; } - return count; } /** diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/RuimRecordsTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/RuimRecordsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..b86725edd7e5f8adf080cd9e20b9d2c1784b8ee2 --- /dev/null +++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/RuimRecordsTest.java @@ -0,0 +1,88 @@ +/* Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package com.android.internal.telephony.uicc; + +import org.mockito.Mock; +import static org.mockito.Mockito.*; +import static org.junit.Assert.*; +import org.mockito.MockitoAnnotations; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import com.android.internal.telephony.TelephonyTest; + +import android.content.Context; +import android.os.AsyncResult; +import android.os.HandlerThread; + +public class RuimRecordsTest extends TelephonyTest { + + private RuimRecords mRuimRecords; + + private class RuimRecordsTestHandler extends HandlerThread { + private RuimRecordsTestHandler(String name) { + super(name); + } + + @Override + public void onLooperPrepared() { + mRuimRecords = new RuimRecords(mUiccCardApplication3gpp2, mContext, mSimulatedCommands); + setReady(true); + } + } + + @Before + public void setUp() throws Exception { + super.setUp(this.getClass().getSimpleName()); + new RuimRecordsTestHandler(TAG).start(); + waitUntilReady(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + public void testCsimImsiLoaded() { + RuimRecords.EfCsimImsimLoaded mImsiLoaded = mRuimRecords.new EfCsimImsimLoaded(); + AsyncResult ar = new AsyncResult(null, null, null); + mImsiLoaded.onRecordLoaded(ar); + String mccmnc = mRuimRecords.getOperatorNumeric(); + assertNull(mccmnc); + + byte[] byteArray = new byte[]{0,19,3,75,68,88,99,(byte)128,(byte)209,0}; + AsyncResult ar2 = new AsyncResult(null, byteArray, null); + mImsiLoaded.onRecordLoaded(ar2); + mccmnc = mRuimRecords.getOperatorNumeric(); + assertNotNull(mccmnc); + assertEquals("31000", mccmnc); + } +}