Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit cf53a4ab authored by Shishir Agrawal's avatar Shishir Agrawal
Browse files

Delay certain SIM_STATE_CHANGE broadcasts.

Delay "loaded" and "locked" broadcasts till until the SubInfo system is ready.

Bug: 18156403
Change-Id: I43aa71354fc2551d0692751935abcbd13f6bd7fc
parent 6095eb5a
Loading
Loading
Loading
Loading
+108 −76
Original line number Original line Diff line number Diff line
@@ -16,6 +16,8 @@


package com.android.internal.telephony;
package com.android.internal.telephony;


import static android.Manifest.permission.READ_PHONE_STATE;

import android.app.ActivityManagerNative;
import android.app.ActivityManagerNative;
import android.content.BroadcastReceiver;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Context;
@@ -35,8 +37,10 @@ import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionInfo;
import android.telephony.TelephonyManager;
import android.telephony.TelephonyManager;
import com.android.internal.telephony.uicc.IccCardProxy;
import com.android.internal.telephony.uicc.IccConstants;
import com.android.internal.telephony.uicc.IccConstants;
import com.android.internal.telephony.uicc.IccFileHandler;
import com.android.internal.telephony.uicc.IccFileHandler;
import com.android.internal.telephony.uicc.IccRecords;
import com.android.internal.telephony.uicc.IccUtils;
import com.android.internal.telephony.uicc.IccUtils;
import android.text.TextUtils;
import android.text.TextUtils;


@@ -49,11 +53,11 @@ public class SubscriptionInfoUpdater extends Handler {
    private static final String LOG_TAG = "SubscriptionInfoUpdater";
    private static final String LOG_TAG = "SubscriptionInfoUpdater";
    private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount();
    private static final int PROJECT_SIM_NUM = TelephonyManager.getDefault().getPhoneCount();


    private static final int EVENT_QUERY_ICCID_DONE = 1;
    private static final int EVENT_SIM_LOCKED_QUERY_ICCID_DONE = 1;
    private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2;
    private static final int EVENT_GET_NETWORK_SELECTION_MODE_DONE = 2;
    private static final int EVENT_SIM_LOADED = 3;
    private static final int EVENT_SIM_LOADED = 3;
    private static final int EVENT_SIM_ABSENT = 4;
    private static final int EVENT_SIM_ABSENT = 4;
    private static final int EVENT_SIM_READY_OR_LOCKED = 5;
    private static final int EVENT_SIM_LOCKED = 5;


    private static final String ICCID_STRING_FOR_NO_SIM = "";
    private static final String ICCID_STRING_FOR_NO_SIM = "";
    /**
    /**
@@ -84,16 +88,10 @@ public class SubscriptionInfoUpdater extends Handler {


    private static Phone[] mPhone;
    private static Phone[] mPhone;
    private static Context mContext = null;
    private static Context mContext = null;
    private static IccFileHandler[] mFh = new IccFileHandler[PROJECT_SIM_NUM];
    private static String mIccId[] = new String[PROJECT_SIM_NUM];
    private static String mIccId[] = new String[PROJECT_SIM_NUM];
    private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
    private static int[] mInsertSimState = new int[PROJECT_SIM_NUM];
    private static TelephonyManager mTelephonyMgr = null;
    private SubscriptionManager mSubscriptionManager = null;
    private SubscriptionManager mSubscriptionManager = null;


    // To prevent repeatedly update flow every time receiver SIM_STATE_CHANGE
    private static boolean mNeedUpdate = true;


    public SubscriptionInfoUpdater(Context context, Phone[] phoneProxy, CommandsInterface[] ci) {
    public SubscriptionInfoUpdater(Context context, Phone[] phoneProxy, CommandsInterface[] ci) {
        logd("Constructor invoked");
        logd("Constructor invoked");


@@ -103,6 +101,8 @@ public class SubscriptionInfoUpdater extends Handler {


        IntentFilter intentFilter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        IntentFilter intentFilter = new IntentFilter(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        mContext.registerReceiver(sReceiver, intentFilter);
        mContext.registerReceiver(sReceiver, intentFilter);
        intentFilter = new IntentFilter(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED);
        mContext.registerReceiver(sReceiver, intentFilter);
    }
    }


    private final BroadcastReceiver sReceiver = new  BroadcastReceiver() {
    private final BroadcastReceiver sReceiver = new  BroadcastReceiver() {
@@ -110,35 +110,40 @@ public class SubscriptionInfoUpdater extends Handler {
        public void onReceive(Context context, Intent intent) {
        public void onReceive(Context context, Intent intent) {
            logd("[Receiver]+");
            logd("[Receiver]+");
            String action = intent.getAction();
            String action = intent.getAction();
            int slotId;
            logd("Action: " + action);
            logd("Action: " + action);


            if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
            if (!action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED) &&
                String simStatus = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
                !action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {
                slotId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
                return;
            }

            int slotId = intent.getIntExtra(PhoneConstants.SLOT_KEY,
                    SubscriptionManager.INVALID_SIM_SLOT_INDEX);
                    SubscriptionManager.INVALID_SIM_SLOT_INDEX);
                logd("slotId: " + slotId + " simStatus: " + simStatus);
            logd("slotId: " + slotId);
            if (slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
            if (slotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
                return;
                return;
            }
            }
                if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(simStatus)

                        || IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)
            String simStatus = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE);
                        || IccCardConstants.INTENT_VALUE_ICC_INTERNAL_LOCKED.equals(simStatus)) {
            logd("simStatus: " + simStatus);
                    //TODO: Use RetryManager to limit number of retries and do a exponential backoff

                    if (((PhoneProxy)mPhone[slotId]).getIccFileHandler() != null) {
            if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) {
                        sendMessage(obtainMessage(EVENT_SIM_READY_OR_LOCKED, slotId, -1));
                if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(simStatus)) {
                    sendMessage(obtainMessage(EVENT_SIM_ABSENT, slotId, -1));
                } else {
                } else {
                        intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE,
                    logd("Ignoring simStatus: " + simStatus);
                                IccCardConstants.INTENT_VALUE_ICC_INTERNAL_LOCKED);
                        ActivityManagerNative.broadcastStickyIntent(intent,
                                "android.permission.READ_PHONE_STATE", UserHandle.USER_ALL);
                }
                }
            } else if (action.equals(IccCardProxy.ACTION_INTERNAL_SIM_STATE_CHANGED)) {
                if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(simStatus)) {
                    String reason = intent.getStringExtra(
                        IccCardConstants.INTENT_KEY_LOCKED_REASON);
                    sendMessage(obtainMessage(EVENT_SIM_LOCKED, slotId, -1, reason));
                } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(simStatus)) {
                } else if (IccCardConstants.INTENT_VALUE_ICC_LOADED.equals(simStatus)) {
                    int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                    int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
                            SubscriptionManager.INVALID_SUBSCRIPTION_ID);
                            SubscriptionManager.INVALID_SUBSCRIPTION_ID);
                    sendMessage(obtainMessage(EVENT_SIM_LOADED, slotId, subId));
                    sendMessage(obtainMessage(EVENT_SIM_LOADED, slotId, subId));
                } else if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(simStatus)) {
                } else {
                    sendMessage(obtainMessage(EVENT_SIM_ABSENT, slotId, -1));
                    logd("Ignoring simStatus: " + simStatus);
                }
                }
            }
            }
            logd("[Receiver]-");
            logd("[Receiver]-");
@@ -181,11 +186,12 @@ public class SubscriptionInfoUpdater extends Handler {


    @Override
    @Override
    public void handleMessage(Message msg) {
    public void handleMessage(Message msg) {
        AsyncResult ar = (AsyncResult)msg.obj;
        switch (msg.what) {
        switch (msg.what) {
            case EVENT_QUERY_ICCID_DONE: {
            case EVENT_SIM_LOCKED_QUERY_ICCID_DONE: {
                Integer slotId = (Integer)ar.userObj;
                AsyncResult ar = (AsyncResult)msg.obj;
                logd("handleMessage : <EVENT_QUERY_ICCID_DONE> SIM" + (slotId + 1));
                QueryIccIdUserObj uObj = (QueryIccIdUserObj) ar.userObj;
                int slotId = uObj.slotId;
                logd("handleMessage : <EVENT_SIM_LOCKED_QUERY_ICCID_DONE> SIM" + (slotId + 1));
                if (ar.exception == null) {
                if (ar.exception == null) {
                    if (ar.result != null) {
                    if (ar.result != null) {
                        byte[] data = (byte[])ar.result;
                        byte[] data = (byte[])ar.result;
@@ -199,13 +205,16 @@ public class SubscriptionInfoUpdater extends Handler {
                    logd("Query IccId fail: " + ar.exception);
                    logd("Query IccId fail: " + ar.exception);
                }
                }
                logd("sIccId[" + slotId + "] = " + mIccId[slotId]);
                logd("sIccId[" + slotId + "] = " + mIccId[slotId]);
                if (isAllIccIdQueryDone() && mNeedUpdate) {
                if (isAllIccIdQueryDone()) {
                    updateSubscriptionInfoByIccId();
                    updateSubscriptionInfoByIccId();
                }
                }
                broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOCKED,
                                         uObj.reason);
                break;
                break;
            }
            }


            case EVENT_GET_NETWORK_SELECTION_MODE_DONE: {
            case EVENT_GET_NETWORK_SELECTION_MODE_DONE: {
                AsyncResult ar = (AsyncResult)msg.obj;
                Integer slotId = (Integer)ar.userObj;
                Integer slotId = (Integer)ar.userObj;
                if (ar.exception == null && ar.result != null) {
                if (ar.exception == null && ar.result != null) {
                    int[] modes = (int[])ar.result;
                    int[] modes = (int[])ar.result;
@@ -226,8 +235,8 @@ public class SubscriptionInfoUpdater extends Handler {
                handleSimAbsent(msg.arg1);
                handleSimAbsent(msg.arg1);
                break;
                break;


            case EVENT_SIM_READY_OR_LOCKED:
            case EVENT_SIM_LOCKED:
                handleSimReadyOrLocked(msg.arg1);
                handleSimLocked(msg.arg1, (String) msg.obj);
                break;
                break;


            default:
            default:
@@ -235,20 +244,60 @@ public class SubscriptionInfoUpdater extends Handler {
        }
        }
    }
    }


    private void handleSimReadyOrLocked(int slotId) {
    private static class QueryIccIdUserObj {
        public String reason;
        public int slotId;

        QueryIccIdUserObj(String reason, int slotId) {
            this.reason = reason;
            this.slotId = slotId;
        }
    };

    private void handleSimLocked(int slotId, String reason) {
        if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
        if (mIccId[slotId] != null && mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
            logd("SIM" + (slotId + 1) + " hot plug in");
            logd("SIM" + (slotId + 1) + " hot plug in");
            mIccId[slotId] = null;
            mIccId[slotId] = null;
            mNeedUpdate = true;
        }
        }


        queryIccId(slotId);

        IccFileHandler fileHandler = mPhone[slotId].getIccCard() == null ? null :
                mPhone[slotId].getIccCard().getIccFileHandler();

        if (fileHandler != null) {
            String iccId = mIccId[slotId];
            if (iccId == null) {
                logd("Querying IccId");
                fileHandler.loadEFTransparent(IccConstants.EF_ICCID,
                        obtainMessage(EVENT_SIM_LOCKED_QUERY_ICCID_DONE,
                                new QueryIccIdUserObj(reason, slotId)));
            } else {
                logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId);
            }
        } else {
            logd("sFh[" + slotId + "] is null, ignore");
        }
    }
    }


    private void handleSimLoaded(int slotId, int subId) {
    private void handleSimLoaded(int slotId, int subId) {
        queryIccId(slotId);
        logd("handleSimStateLoadedInternal: slotId: " + slotId + " subId: " + subId);
        if (mTelephonyMgr == null) {

            mTelephonyMgr = TelephonyManager.from(mContext);
        // The SIM should be loaded at this state, but it is possible in cases such as SIM being
        // removed or a refresh RESET that the IccRecords could be null. The right behavior is to
        // not broadcast the SIM loaded.
        IccRecords records = mPhone[slotId].getIccCard().getIccRecords();
        if (records == null) {  // Possibly a race condition.
            logd("onRecieve: IccRecords null");
            return;
        }
        if (records.getIccId() == null) {
            logd("onRecieve: IccID null");
            return;
        }
        mIccId[slotId] = records.getIccId();

        if (isAllIccIdQueryDone()) {
            updateSubscriptionInfoByIccId();
        }
        }


        if (SubscriptionManager.isValidSubscriptionId(subId)) {
        if (SubscriptionManager.isValidSubscriptionId(subId)) {
@@ -322,57 +371,26 @@ public class SubscriptionInfoUpdater extends Handler {
        } else {
        } else {
            logd("Invalid subId, could not update ContentResolver");
            logd("Invalid subId, could not update ContentResolver");
        }
        }

        broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
    }
    }


    private void handleSimAbsent(int slotId) {
    private void handleSimAbsent(int slotId) {
        if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
        if (mIccId[slotId] != null && !mIccId[slotId].equals(ICCID_STRING_FOR_NO_SIM)) {
            logd("SIM" + (slotId + 1) + " hot plug out");
            logd("SIM" + (slotId + 1) + " hot plug out");
            mNeedUpdate = true;
        }
        }
        mFh[slotId] = null;
        mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
        mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
        if (isAllIccIdQueryDone() && mNeedUpdate) {
        if (isAllIccIdQueryDone()) {
            updateSubscriptionInfoByIccId();
            updateSubscriptionInfoByIccId();
        }
        }
    }
    }


    private void queryIccId(int slotId) {
        logd("queryIccId: slotid=" + slotId);
        if (mFh[slotId] == null) {
            logd("Getting IccFileHandler");
            if (mPhone[slotId].getIccCard() != null) {
                mFh[slotId] = mPhone[slotId].getIccCard().getIccFileHandler();
            }
            /** Just in case file handler cannot be obtained from IccCard directly, we can use the
             * earlier way of getting it from phone */
            // TODO remove this if block
             if (mFh[slotId] == null) {
                logd("queryIccId: Could not get IccFileHandler directly from IccCard");
                mFh[slotId] = ((PhoneProxy) mPhone[slotId]).getIccFileHandler();
            }
        }

        if (mFh[slotId] != null) {
            String iccId = mIccId[slotId];
            if (iccId == null) {
                logd("Querying IccId");
                mFh[slotId].loadEFTransparent(IccConstants.EF_ICCID,
                        obtainMessage(EVENT_QUERY_ICCID_DONE, new Integer(slotId)));
            } else {
                logd("NOT Querying IccId its already set sIccid[" + slotId + "]=" + iccId);
            }
        } else {
            logd("sFh[" + slotId + "] is null, ignore");
        }
    }

    /**
    /**
     * TODO: Simplify more, as no one is interested in what happened
     * TODO: Simplify more, as no one is interested in what happened
     * only what the current list contains.
     * only what the current list contains.
     */
     */
    synchronized private void updateSubscriptionInfoByIccId() {
    synchronized private void updateSubscriptionInfoByIccId() {
        logd("updateSubscriptionInfoByIccId:+ Start");
        logd("updateSubscriptionInfoByIccId:+ Start");
        mNeedUpdate = false;


        mSubscriptionManager.clearSubscriptionInfo();
        mSubscriptionManager.clearSubscriptionInfo();


@@ -521,6 +539,20 @@ public class SubscriptionInfoUpdater extends Handler {
        return newSim;
        return newSim;
    }
    }


    private void broadcastSimStateChanged(int slotId, String state, String reason) {
        Intent i = new Intent(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
        i.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
        i.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
        i.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, state);
        i.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
        SubscriptionManager.putPhoneIdAndSubIdExtra(i, slotId);
        logd("Broadcasting intent ACTION_SIM_STATE_CHANGED " +
             IccCardConstants.INTENT_VALUE_ICC_LOADED + " reason " + null +
             " for mCardIndex : " + slotId);
        ActivityManagerNative.broadcastStickyIntent(i, READ_PHONE_STATE,
                UserHandle.USER_ALL);
    }

    public void dispose() {
    public void dispose() {
        logd("[dispose]");
        logd("[dispose]");
        mContext.unregisterReceiver(sReceiver);
        mContext.unregisterReceiver(sReceiver);
+30 −3
Original line number Original line Diff line number Diff line
@@ -119,6 +119,8 @@ public class IccCardProxy extends Handler implements IccCard {
    private boolean mInitialized = false;
    private boolean mInitialized = false;
    private State mExternalState = State.UNKNOWN;
    private State mExternalState = State.UNKNOWN;


    public static final String ACTION_INTERNAL_SIM_STATE_CHANGED = "android.intent.action.internal_sim_state_changed";

    public IccCardProxy(Context context, CommandsInterface ci, int cardIndex) {
    public IccCardProxy(Context context, CommandsInterface ci, int cardIndex) {
        if (DBG) log("ctor: ci=" + ci + " cardIndex=" + cardIndex);
        if (DBG) log("ctor: ci=" + ci + " cardIndex=" + cardIndex);
        mContext = context;
        mContext = context;
@@ -364,7 +366,7 @@ public class IccCardProxy extends Handler implements IccCard {
    }
    }


    private void onRecordsLoaded() {
    private void onRecordsLoaded() {
        broadcastIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
        broadcastInternalIccStateChangedIntent(IccCardConstants.INTENT_VALUE_ICC_LOADED, null);
    }
    }


    private void updateIccAvailability() {
    private void updateIccAvailability() {
@@ -513,6 +515,24 @@ public class IccCardProxy extends Handler implements IccCard {
        }
        }
    }
    }


    private void broadcastInternalIccStateChangedIntent(String value, String reason) {
        synchronized (mLock) {
            if (mCardIndex == null) {
                loge("broadcastInternalIccStateChangedIntent: Card Index is not set; Return!!");
                return;
            }

            Intent intent = new Intent(ACTION_INTERNAL_SIM_STATE_CHANGED);
            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
            intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone");
            intent.putExtra(IccCardConstants.INTENT_KEY_ICC_STATE, value);
            intent.putExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON, reason);
            SubscriptionManager.putPhoneIdAndSubIdExtra(intent, mCardIndex);
            log("Sending intent ACTION_INTERNAL_SIM_STATE_CHANGED" + " for mCardIndex : " + mCardIndex);
            ActivityManagerNative.broadcastStickyIntent(intent, null, UserHandle.USER_ALL);
        }
    }

    private void setExternalState(State newState, boolean override) {
    private void setExternalState(State newState, boolean override) {
        synchronized (mLock) {
        synchronized (mLock) {
            if (mCardIndex == null || !SubscriptionManager.isValidSlotId(mCardIndex)) {
            if (mCardIndex == null || !SubscriptionManager.isValidSlotId(mCardIndex)) {
@@ -527,8 +547,15 @@ public class IccCardProxy extends Handler implements IccCard {
            mExternalState = newState;
            mExternalState = newState;
            loge("setExternalState: set mCardIndex=" + mCardIndex + " mExternalState=" + mExternalState);
            loge("setExternalState: set mCardIndex=" + mCardIndex + " mExternalState=" + mExternalState);
            setSystemProperty(PROPERTY_SIM_STATE, mCardIndex, getState().toString());
            setSystemProperty(PROPERTY_SIM_STATE, mCardIndex, getState().toString());

            // For locked states, we should be sending internal broadcast.
            if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(getIccStateIntentString(mExternalState))) {
                broadcastInternalIccStateChangedIntent(getIccStateIntentString(mExternalState),
                        getIccStateReason(mExternalState));
            } else {
                broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
                broadcastIccStateChangedIntent(getIccStateIntentString(mExternalState),
                        getIccStateReason(mExternalState));
                        getIccStateReason(mExternalState));
            }
            // TODO: Need to notify registrants for other states as well.
            // TODO: Need to notify registrants for other states as well.
            if ( State.ABSENT == mExternalState) {
            if ( State.ABSENT == mExternalState) {
                mAbsentRegistrants.notifyRegistrants();
                mAbsentRegistrants.notifyRegistrants();