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

Commit a5ea9112 authored by Robert Greenwalt's avatar Robert Greenwalt
Browse files

Clean up the switch state machine.

Handle inputs while in any state.  This is made much easier by removing
the synchronous calls - any time you find a synchronous call into a state
machine you're doing something wrong.

Also rework the timeout system - it was bad in that it injected the
new session id whenever you start an new session so old timers were
always acted upon.

Also should eliminate/reduce the duplicate ALLOW_DATA RIL calls.

bug:20076867
Change-Id: Ibabd76fad0759dd9c403ac8ee017958e38df56a5
parent 4c4b8afa
Loading
Loading
Loading
Loading
+35 −52
Original line number Diff line number Diff line
@@ -52,6 +52,7 @@ public class ProxyController {
    private static final int EVENT_START_RC_RESPONSE        = 2;
    private static final int EVENT_APPLY_RC_RESPONSE        = 3;
    private static final int EVENT_FINISH_RC_RESPONSE       = 4;
    private static final int EVENT_TIMEOUT                  = 5;

    private static final int SET_RC_STATUS_IDLE             = 0;
    private static final int SET_RC_STATUS_STARTING         = 1;
@@ -109,8 +110,6 @@ public class ProxyController {
    private int[] mNewRadioAccessFamily;
    private int[] mOldRadioAccessFamily;

    // runnable for radio capability request timeout handling
    RadioCapabilityRunnable mSetRadioCapabilityRunnable;

    //***** Class Methods
    public static ProxyController getInstance(Context context, PhoneProxy[] phoneProxy,
@@ -144,8 +143,6 @@ public class ProxyController {
        mCurrentLogicalModemIds = new String[mProxyPhones.length];
        mNewLogicalModemIds = new String[mProxyPhones.length];

        mSetRadioCapabilityRunnable = new RadioCapabilityRunnable();

        // wake lock for set radio capability
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
@@ -257,8 +254,8 @@ public class ProxyController {

        // Start timer to make sure all phones respond within a specific time interval.
        // Will send FINISH if a timeout occurs.
        mSetRadioCapabilityRunnable.setTimeoutState(mRadioCapabilitySessionId);
        mHandler.postDelayed(mSetRadioCapabilityRunnable, SET_RC_TIMEOUT_WAITING_MSEC);
        Message msg = mHandler.obtainMessage(EVENT_TIMEOUT, mRadioCapabilitySessionId, 0);
        mHandler.sendMessageDelayed(msg, SET_RC_TIMEOUT_WAITING_MSEC);

        synchronized (mSetRadioAccessFamilyStatus) {
            logd("setRadioCapability: new request session id=" + mRadioCapabilitySessionId);
@@ -317,6 +314,10 @@ public class ProxyController {
                    onFinishRadioCapabilityResponse(msg);
                    break;

                case EVENT_TIMEOUT:
                    onTimeoutRadioCapability(msg);
                    break;

                default:
                    break;
            }
@@ -435,13 +436,13 @@ public class ProxyController {
            } else {
                logd("onNotificationRadioCapabilityChanged: phoneId=" + id + " status=SUCCESS");
                mSetRadioAccessFamilyStatus[id] = SET_RC_STATUS_SUCCESS;
                // The modems may have been restarted and forgotten this
                mDctController.retryAttach(id);
                mProxyPhones[id].radioCapabilityUpdated(rc);
            }

            mRadioAccessFamilyStatusCounter--;
            if (mRadioAccessFamilyStatusCounter == 0) {
                logd("onNotificationRadioCapabilityChanged: removing callback from handler");
                mHandler.removeCallbacks(mSetRadioCapabilityRunnable);
                logd("onNotificationRadioCapabilityChanged: APPLY URC success=" +
                        mTransactionFailed);
                issueFinish(mRadioCapabilitySessionId);
@@ -470,6 +471,29 @@ public class ProxyController {
        }
    }

    private void onTimeoutRadioCapability(Message msg) {
        if (msg.arg1 != mRadioCapabilitySessionId) {
           logd("RadioCapability timeout: Ignore msg.arg1=" + msg.arg1 +
                   "!= mRadioCapabilitySessionId=" + mRadioCapabilitySessionId);
            return;
        }

        synchronized(mSetRadioAccessFamilyStatus) {
            // timed-out.  Clean up as best we can
            for (int i = 0; i < mProxyPhones.length; i++) {
                logd("RadioCapability timeout: mSetRadioAccessFamilyStatus[" + i + "]=" +
                        mSetRadioAccessFamilyStatus[i]);
            }

            // Increment the sessionId as we are completing the transaction below
            // so we don't want it completed when the FINISH phase is done.
            int uniqueDifferentId = mUniqueIdGenerator.getAndIncrement();
            // send FINISH request with fail status and then uniqueDifferentId
            mTransactionFailed = true;
            issueFinish(uniqueDifferentId);
        }
    }

    private void issueFinish(int sessionId) {
        // Issue FINISH
        synchronized(mSetRadioAccessFamilyStatus) {
@@ -511,6 +535,9 @@ public class ProxyController {
            intent.putParcelableArrayListExtra(TelephonyIntents.EXTRA_RADIO_ACCESS_FAMILY,
                    phoneRAFList);

            // make messages about the old transaction obsolete (specifically the timeout)
            mRadioCapabilitySessionId = mUniqueIdGenerator.getAndIncrement();

            // Reinitialize
            clearTransaction();
        } else {
@@ -559,50 +586,6 @@ public class ProxyController {
                requestRC, mHandler.obtainMessage(eventId));
    }

    /**
     * RadioCapabilityRunnable is used to check
     * if radio capability request's response is out of date.
     * <p>
     * Note that the setRadioCapability will be stopped directly and send FINISH
     * with fail status to all logical modems. and send out fail intent
     *
     */
    private class RadioCapabilityRunnable implements Runnable {
        private int mSessionId;
        public  RadioCapabilityRunnable() {
        }

        public void setTimeoutState(int sessionId) {
            mSessionId = sessionId;
        }

        @Override
        public void run() {
            if (mSessionId != mRadioCapabilitySessionId) {
                logd("RadioCapability timeout: Ignore mSessionId=" + mSessionId
                       + "!= mRadioCapabilitySessionId=" + mRadioCapabilitySessionId);
                return;
            }

            synchronized(mSetRadioAccessFamilyStatus) {
                // timed-out.  Clean up as best we can
                for (int i = 0; i < mProxyPhones.length; i++) {
                    logd("RadioCapability timeout: mSetRadioAccessFamilyStatus[" + i + "]=" +
                            mSetRadioAccessFamilyStatus[i]);
                }

                // Increment the sessionId as we are completing the transaction below
                // so we don't want it completed when the FINISH phase is done.
                int uniqueDifferentId = mUniqueIdGenerator.getAndIncrement();

                // send FINISH request with fail status and then uniqueDifferentId
                mTransactionFailed = true;
                issueFinish(uniqueDifferentId);
                completeRadioCapabilityTransaction();
            }
        }
    }

    // This method will return max number of raf bits supported from the raf
    // values currently stored in all phone objects
    public int getMaxRafSupported() {
+4 −1
Original line number Diff line number Diff line
@@ -712,7 +712,10 @@ public final class RIL extends BaseCommands implements CommandsInterface {
    // FIXME This API should take an AID and slot ID
    public void setDataAllowed(boolean allowed, Message result) {
        RILRequest rr = RILRequest.obtain(RIL_REQUEST_ALLOW_DATA, result);
        if (RILJ_LOGD) riljLog(rr.serialString() + "> " + requestToString(rr.mRequest));
        if (RILJ_LOGD) {
            riljLog(rr.serialString() + "> " + requestToString(rr.mRequest) +
                    " allowed: " + allowed);
        }

        rr.mParcel.writeInt(1);
        rr.mParcel.writeInt(allowed ? 1 : 0);
+18 −58
Original line number Diff line number Diff line
@@ -35,27 +35,21 @@ public class DcSwitchAsyncChannel extends AsyncChannel {
    // ***** Event codes for driving the state machine
    private static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER + 0x00002000;
    static final int REQ_CONNECT =                    BASE + 0;
    static final int RSP_CONNECT = BASE + 1;
    static final int REQ_DISCONNECT = BASE + 2;
    static final int RSP_DISCONNECT = BASE + 3;
    static final int REQ_DISCONNECT_ALL = BASE + 4;
    static final int RSP_DISCONNECT_ALL = BASE + 5;
    static final int REQ_IS_IDLE_STATE = BASE + 6;
    static final int RSP_IS_IDLE_STATE = BASE + 7;
    static final int REQ_IS_IDLE_OR_DETACHING_STATE = BASE + 8;
    static final int RSP_IS_IDLE_OR_DETACHING_STATE = BASE + 9;
    static final int EVENT_DATA_ATTACHED = BASE + 10;
    static final int EVENT_DATA_DETACHED = BASE + 11;
    static final int REQ_RETRY_CONNECT  =             BASE + 1;
    static final int REQ_DISCONNECT_ALL =             BASE + 2;
    static final int REQ_IS_IDLE_STATE =              BASE + 3;
    static final int RSP_IS_IDLE_STATE =              BASE + 4;
    static final int REQ_IS_IDLE_OR_DETACHING_STATE = BASE + 5;
    static final int RSP_IS_IDLE_OR_DETACHING_STATE = BASE + 6;
    static final int EVENT_DATA_ATTACHED =            BASE + 7;
    static final int EVENT_DATA_DETACHED =            BASE + 8;

    private static final int CMD_TO_STRING_COUNT = EVENT_DATA_DETACHED - BASE + 1;
    private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
    static {
        sCmdToString[REQ_CONNECT - BASE] = "REQ_CONNECT";
        sCmdToString[RSP_CONNECT - BASE] = "RSP_CONNECT";
        sCmdToString[REQ_DISCONNECT - BASE] = "REQ_DISCONNECT";
        sCmdToString[RSP_DISCONNECT - BASE] = "RSP_DISCONNECT";
        sCmdToString[REQ_RETRY_CONNECT - BASE] = "REQ_RETRY_CONNECT";
        sCmdToString[REQ_DISCONNECT_ALL - BASE] = "REQ_DISCONNECT_ALL";
        sCmdToString[RSP_DISCONNECT_ALL - BASE] = "RSP_DISCONNECT_ALL";
        sCmdToString[REQ_IS_IDLE_STATE - BASE] = "REQ_IS_IDLE_STATE";
        sCmdToString[RSP_IS_IDLE_STATE - BASE] = "RSP_IS_IDLE_STATE";
        sCmdToString[REQ_IS_IDLE_OR_DETACHING_STATE - BASE] = "REQ_IS_IDLE_OR_DETACHING_STATE";
@@ -95,52 +89,18 @@ public class DcSwitchAsyncChannel extends AsyncChannel {
        tagId = id;
    }

    private int rspConnect(Message response) {
        int retVal = response.arg1;
        if (DBG) log("rspConnect=" + retVal);
        return retVal;
    }

    public int connectSync(RequestInfo apnRequest) {
        Message response = sendMessageSynchronously(REQ_CONNECT, apnRequest);
        if ((response != null) && (response.what == RSP_CONNECT)) {
            return rspConnect(response);
        } else {
            if (DBG) log("rspConnect error response=" + response);
            return PhoneConstants.APN_REQUEST_FAILED;
        }
    public int connect(RequestInfo apnRequest) {
        sendMessage(REQ_CONNECT, apnRequest);
        return PhoneConstants.APN_REQUEST_STARTED;
    }

    private int rspDisconnect(Message response) {
        int retVal = response.arg1;
        if (DBG) log("rspDisconnect=" + retVal);
        return retVal;
    public void retryConnect() {
        sendMessage(REQ_RETRY_CONNECT);
    }

    public int disconnectSync(RequestInfo apnRequest) {
        Message response = sendMessageSynchronously(REQ_DISCONNECT, apnRequest);
        if ((response != null) && (response.what == RSP_DISCONNECT)) {
            return rspDisconnect(response);
        } else {
            if (DBG) log("rspDisconnect error response=" + response);
            return PhoneConstants.APN_REQUEST_FAILED;
        }
    }

    private int rspDisconnectAll(Message response) {
        int retVal = response.arg1;
        if (DBG) log("rspDisconnectAll=" + retVal);
        return retVal;
    }

    public int disconnectAllSync() {
        Message response = sendMessageSynchronously(REQ_DISCONNECT_ALL);
        if ((response != null) && (response.what == RSP_DISCONNECT_ALL)) {
            return rspDisconnectAll(response);
        } else {
            if (DBG) log("rspDisconnectAll error response=" + response);
            return PhoneConstants.APN_REQUEST_FAILED;
        }
    public int disconnectAll() {
        sendMessage(REQ_DISCONNECT_ALL);
        return PhoneConstants.APN_REQUEST_STARTED;
    }

    public void notifyDataAttached() {
+61 −45
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import com.android.internal.telephony.PhoneBase;
import com.android.internal.telephony.PhoneProxy;
import com.android.internal.telephony.dataconnection.DcSwitchAsyncChannel.RequestInfo;

import android.os.AsyncResult;
import android.os.Message;
import android.telephony.Rlog;

@@ -37,6 +38,8 @@ public class DcSwitchStateMachine extends StateMachine {
    // ***** Event codes for driving the state machine
    private static final int BASE = Protocol.BASE_DATA_CONNECTION_TRACKER + 0x00001000;
    private static final int EVENT_CONNECTED    = BASE + 0;
    private static final int EVENT_DATA_ALLOWED = BASE + 1;
    private static final int CMD_RETRY_ATTACH   = BASE + 2;

    private int mId;
    private Phone mPhone;
@@ -89,21 +92,24 @@ public class DcSwitchStateMachine extends StateMachine {

            switch (msg.what) {
                case DcSwitchAsyncChannel.REQ_CONNECT: {
                    if (DBG) {
                        log("IdleState: REQ_CONNECT");
                    RequestInfo apnRequest = (RequestInfo)msg.obj;
                    if (DBG) log("IdleState: REQ_CONNECT, apnRequest=" + apnRequest);
                    transitionTo(mAttachingState);
                    retVal = HANDLED;
                    break;
                }

                    PhoneBase pb = (PhoneBase)((PhoneProxy)mPhone).getActivePhone();
                    pb.mCi.setDataAllowed(true, null);
                case DcSwitchAsyncChannel.REQ_DISCONNECT_ALL: {
                    if (DBG) log("AttachingState: REQ_DISCONNECT_ALL" );

                    mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT,
                            PhoneConstants.APN_REQUEST_STARTED);
                    // Shouldn't have any requests, but why not try..
                    DctController.getInstance().releaseAllRequests(mId);

                    transitionTo(mAttachingState);
                    retVal = HANDLED;
                    break;
                }


                case DcSwitchAsyncChannel.EVENT_DATA_ATTACHED:
                    if (DBG) {
                        log("AttachingState: EVENT_DATA_ATTACHED");
@@ -132,9 +138,17 @@ public class DcSwitchStateMachine extends StateMachine {
    }

    private class AttachingState extends State {
        private int mCurrentAllowedSequence = 0;
        @Override
        public void enter() {
            log("AttachingState: enter");
            doEnter();
        }

        private void doEnter() {
            final PhoneBase pb = (PhoneBase)((PhoneProxy)mPhone).getActivePhone();
            pb.mCi.setDataAllowed(true, obtainMessage(EVENT_DATA_ALLOWED,
                    ++mCurrentAllowedSequence, 0));
        }

        @Override
@@ -143,36 +157,51 @@ public class DcSwitchStateMachine extends StateMachine {

            switch (msg.what) {
                case DcSwitchAsyncChannel.REQ_CONNECT: {
                    if (DBG) {
                        log("AttachingState: REQ_CONNECT");
                    RequestInfo apnRequest = (RequestInfo)msg.obj;
                    if (DBG) log("AttachingState: REQ_CONNECT, apnRequest=" + apnRequest);

                    // do nothing - wait til we attach and then we'll execute all requests
                    retVal = HANDLED;
                    break;
                }

                    PhoneBase pb = (PhoneBase) ((PhoneProxy) mPhone).getActivePhone();
                    pb.mCi.setDataAllowed(true, null);
                case EVENT_DATA_ALLOWED: {
                    AsyncResult ar = (AsyncResult)msg.obj;
                    if (mCurrentAllowedSequence != msg.arg1) {
                        loge("EVENT_DATA_ATTACHED ignored arg1=" + msg.arg1 + ", seq=" +
                                mCurrentAllowedSequence);
                    } else if (ar.exception != null) {
                        loge("EVENT_DATA_ATTACHED failed, " + ar.exception);
                        transitionTo(mIdleState);
                    }
                    retVal = HANDLED;
                    break;
                }

                    mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT,
                            PhoneConstants.APN_REQUEST_STARTED);
                case DcSwitchAsyncChannel.REQ_RETRY_CONNECT: {
                    if (DBG) log("AttachingState going to retry");
                    doEnter();
                    retVal = HANDLED;
                    break;
                }

                case DcSwitchAsyncChannel.EVENT_DATA_ATTACHED:
                case DcSwitchAsyncChannel.EVENT_DATA_ATTACHED: {
                    if (DBG) {
                        log("AttachingState: EVENT_DATA_ATTACHED");
                    }
                    transitionTo(mAttachedState);
                    retVal = HANDLED;
                    break;
                }

                case DcSwitchAsyncChannel.REQ_DISCONNECT_ALL: {
                    if (DBG) {
                        log("AttachingState: REQ_DISCONNECT_ALL" );
                    }
                    DctController.getInstance().releaseAllRequests(mId);
                    mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_DISCONNECT_ALL,
                            PhoneConstants.APN_REQUEST_STARTED);

                    transitionTo(mDetachingState);
                    // modem gets unhappy if we try to detach while attaching
                    // wait til attach finishes.
                    deferMessage(msg);
                    retVal = HANDLED;
                    break;
                }
@@ -204,27 +233,9 @@ public class DcSwitchStateMachine extends StateMachine {
            switch (msg.what) {
                case DcSwitchAsyncChannel.REQ_CONNECT: {
                    RequestInfo apnRequest = (RequestInfo)msg.obj;
                    if (DBG) {
                        log("AttachedState: REQ_CONNECT, apnRequest=" + apnRequest);
                    }
                    if (DBG) log("AttachedState: REQ_CONNECT, apnRequest=" + apnRequest);

                    DctController.getInstance().executeRequest(apnRequest);
                    mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT,
                            PhoneConstants.APN_REQUEST_STARTED);

                    retVal = HANDLED;
                    break;
                }
                case DcSwitchAsyncChannel.REQ_DISCONNECT: {
                    RequestInfo apnRequest = (RequestInfo)msg.obj;
                    if (DBG) {
                        log("AttachedState: REQ_DISCONNECT apnRequest=" + apnRequest);
                    }

                    DctController.getInstance().releaseRequest(apnRequest);
                    mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_CONNECT,
                            PhoneConstants.APN_REQUEST_STARTED);

                    retVal = HANDLED;
                    break;
                }
@@ -234,9 +245,6 @@ public class DcSwitchStateMachine extends StateMachine {
                        log("AttachedState: REQ_DISCONNECT_ALL" );
                    }
                    DctController.getInstance().releaseAllRequests(mId);
                    mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_DISCONNECT_ALL,
                            PhoneConstants.APN_REQUEST_STARTED);

                    transitionTo(mDetachingState);
                    retVal = HANDLED;
                    break;
@@ -277,6 +285,16 @@ public class DcSwitchStateMachine extends StateMachine {
            boolean retVal;

            switch (msg.what) {
                case DcSwitchAsyncChannel.REQ_CONNECT: {
                    RequestInfo apnRequest = (RequestInfo)msg.obj;
                    if (DBG) log("DetachingState: REQ_CONNECT, apnRequest=" + apnRequest);

                    // can't process this now - wait until we return to idle
                    deferMessage(msg);
                    retVal = HANDLED;
                    break;
                }

                case DcSwitchAsyncChannel.EVENT_DATA_DETACHED: {
                    if (DBG) {
                        log("DetachingState: EVENT_DATA_DETACHED");
@@ -290,8 +308,6 @@ public class DcSwitchStateMachine extends StateMachine {
                    if (DBG) {
                        log("DetachingState: REQ_DISCONNECT_ALL, already detaching" );
                    }
                    mAc.replyToMessage(msg, DcSwitchAsyncChannel.RSP_DISCONNECT_ALL,
                            PhoneConstants.APN_REQUEST_STARTED);
                    retVal = HANDLED;
                    break;
                }
+20 −2
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ public class DctController extends Handler {
    private static final int EVENT_EXECUTE_ALL_REQUESTS = 102;
    private static final int EVENT_RELEASE_REQUEST = 103;
    private static final int EVENT_RELEASE_ALL_REQUESTS = 104;
    private static final int EVENT_RETRY_ATTACH = 105;

    private static final int EVENT_DATA_ATTACHED = 500;
    private static final int EVENT_DATA_DETACHED = 600;
@@ -276,6 +277,9 @@ public class DctController extends Handler {
            case EVENT_RELEASE_ALL_REQUESTS:
                onReleaseAllRequests(msg.arg1);
                break;
            case EVENT_RETRY_ATTACH:
                onRetryAttach(msg.arg1);
                break;
            default:
                loge("Un-handled message [" + msg.what + "]");
        }
@@ -327,6 +331,11 @@ public class DctController extends Handler {
        sendMessage(obtainMessage(EVENT_RELEASE_ALL_REQUESTS, phoneId, 0));
    }

    public void retryAttach(int phoneId) {
        logd("retryAttach, phone:" + phoneId);
        sendMessage(obtainMessage(EVENT_RETRY_ATTACH, phoneId, 0));
    }

    private void onProcessRequest() {
        //process all requests
        //1. Check all requests and find subscription of the top priority
@@ -354,11 +363,11 @@ public class DctController extends Handler {
            while (iterator.hasNext()) {
                RequestInfo requestInfo = mRequestInfos.get(iterator.next());
                if (getRequestPhoneId(requestInfo.request) == phoneId && !requestInfo.executed) {
                    mDcSwitchAsyncChannel[phoneId].connectSync(requestInfo);
                    mDcSwitchAsyncChannel[phoneId].connect(requestInfo);
                }
            }
        } else {
            mDcSwitchAsyncChannel[activePhoneId].disconnectAllSync();
            mDcSwitchAsyncChannel[activePhoneId].disconnectAll();
        }
    }

@@ -408,6 +417,15 @@ public class DctController extends Handler {
        }
    }

    private void onRetryAttach(int phoneId) {
        final int topPriPhone = getTopPriorityRequestPhoneId();
        logd("onRetryAttach phoneId=" + phoneId + " topPri phone = " + topPriPhone);

        if (phoneId != -1 && phoneId == topPriPhone) {
            mDcSwitchAsyncChannel[phoneId].retryConnect();
        }
    }

    private void onSettingsChange() {
        //Sub Selection
        long dataSubId = mSubController.getDefaultDataSubId();