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

Commit 71873c36 authored by Robert Greenwalt's avatar Robert Greenwalt
Browse files

DO NOT MERGE - 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: I175f267238bc4c7afa82ef27fe3d79a0d5e2eeb1
parent 1b8d2e0d
Loading
Loading
Loading
Loading
+35 −52
Original line number Diff line number Diff line
@@ -53,6 +53,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;
@@ -110,8 +111,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,
@@ -145,8 +144,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);
@@ -258,8 +255,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);
@@ -318,6 +315,10 @@ public class ProxyController {
                    onFinishRadioCapabilityResponse(msg);
                    break;

                case EVENT_TIMEOUT:
                    onTimeoutRadioCapability(msg);
                    break;

                default:
                    break;
            }
@@ -436,13 +437,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);
@@ -471,6 +472,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) {
@@ -512,6 +536,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 {
@@ -560,50 +587,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();