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

Commit efcc3d35 authored by Wink Saville's avatar Wink Saville
Browse files

Cleanup StateMachine LogRec handling and get tests working.

Change-Id: I13107e846812b16f1c95be11626500dbd7a13b2a
parent e340e68f
Loading
Loading
Loading
Loading
+257 −146
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.Vector;

@@ -81,8 +82,8 @@ import java.util.Vector;
 * machine will cause <code>haltedProcessMessage</code> to be invoked.</p>
 *
 * <p>If it is desirable to completely stop the state machine call <code>quit</code> or
 * <code>abort</code>. These will call <code>exit</code> of the current state and its parents, call
 * <code>onQuiting</code> and then exit Thread/Loopers.</p>
 * <code>quitNow</code>. These will call <code>exit</code> of the current state and its parents,
 * call <code>onQuiting</code> and then exit Thread/Loopers.</p>
 *
 * <p>In addition to <code>processMessage</code> each <code>State</code> has
 * an <code>enter</code> method and <code>exit</exit> method which may be overridden.</p>
@@ -444,12 +445,13 @@ public class StateMachine {
     * {@hide}
     */
    public static class LogRec {
        private StateMachine mSm;
        private long mTime;
        private int mWhat;
        private String mInfo;
        private State mState;
        private State mOrgState;
        private State mTransitionToState;
        private IState mState;
        private IState mOrgState;
        private IState mDstState;

        /**
         * Constructor
@@ -461,26 +463,26 @@ public class StateMachine {
         * @param transToState is the state that was transitioned to after the message was
         * processed.
         */
        LogRec(Message msg, String info, State state, State orgState, State transToState) {
            update(msg, info, state, orgState, transToState);
        LogRec(StateMachine sm, Message msg, String info, IState state, IState orgState,
                IState transToState) {
            update(sm, msg, info, state, orgState, transToState);
        }

        /**
         * Update the information in the record.
         * @param state that handled the message
         * @param orgState is the first state the received the message but
         * did not processes the message.
         * @param transToState is the state that was transitioned to after the message was
         * processed.
         * @param orgState is the first state the received the message
         * @param dstState is the state that was the transition target when logging
         */
        public void update(Message msg, String info, State state, State orgState,
                State transToState) {
        public void update(StateMachine sm, Message msg, String info, IState state, IState orgState,
                IState dstState) {
            mSm = sm;
            mTime = System.currentTimeMillis();
            mWhat = (msg != null) ? msg.what : 0;
            mInfo = info;
            mState = state;
            mOrgState = orgState;
            mTransitionToState = transToState;
            mDstState = dstState;
        }

        /**
@@ -507,21 +509,27 @@ public class StateMachine {
        /**
         * @return the state that handled this message
         */
        public State getState() {
        public IState getState() {
            return mState;
        }

        /**
         * @return the original state that received the message.
         * @return the state destination state if a transition is occurring or null if none.
         */
        public State getOriginalState() {
            return mOrgState;
        public IState getDestState() {
            return mDstState;
        }


        /**
         * @return as string
         * @return the original state that received the message.
         */
        public String toString(StateMachine sm) {
        public IState getOriginalState() {
            return mOrgState;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            sb.append("time=");
            Calendar c = Calendar.getInstance();
@@ -532,9 +540,9 @@ public class StateMachine {
            sb.append(" org=");
            sb.append(mOrgState == null ? "<null>" : mOrgState.getName());
            sb.append(" dest=");
            sb.append(mTransitionToState == null ? "<null>" : mTransitionToState.getName());
            sb.append(mDstState == null ? "<null>" : mDstState.getName());
            sb.append(" what=");
            String what = sm.getWhatToString(mWhat);
            String what = mSm != null ? mSm.getWhatToString(mWhat) : "";
            if (TextUtils.isEmpty(what)) {
                sb.append(mWhat);
                sb.append("(0x");
@@ -647,18 +655,19 @@ public class StateMachine {
         * processed.
         *
         */
        synchronized void add(Message msg, String messageInfo, State state, State orgState,
                State transToState) {
        synchronized void add(StateMachine sm, Message msg, String messageInfo, IState state,
                IState orgState,
                IState transToState) {
            mCount += 1;
            if (mLogRecVector.size() < mMaxSize) {
                mLogRecVector.add(new LogRec(msg, messageInfo, state, orgState, transToState));
                mLogRecVector.add(new LogRec(sm, msg, messageInfo, state, orgState, transToState));
            } else {
                LogRec pmi = mLogRecVector.get(mOldestIndex);
                mOldestIndex += 1;
                if (mOldestIndex >= mMaxSize) {
                    mOldestIndex = 0;
                }
                pmi.update(msg, messageInfo, state, orgState, transToState);
                pmi.update(sm, msg, messageInfo, state, orgState, transToState);
            }
        }
    }
@@ -788,36 +797,50 @@ public class StateMachine {
                throw new RuntimeException("StateMachine.handleMessage: " +
                            "The start method not called, received msg: " + msg);
            }
            performTransitions(msgProcessedState);
            performTransitions(msgProcessedState, msg);

            if (mDbg) mSm.log("handleMessage: X");
            // We need to check if mSm == null here as we could be quitting.
            if (mDbg && mSm != null) mSm.log("handleMessage: X");
        }

        /**
         * Do any transitions
         * @param msgProcessedState is the state that processed the message
         */
        private void performTransitions(State msgProcessedState) {
        private void performTransitions(State msgProcessedState, Message msg) {
            /**
             * If transitionTo has been called, exit and then enter
             * the appropriate states. We loop on this to allow
             * enter and exit methods to use transitionTo.
             */
            State destState = null;
            State orgState = mStateStack[mStateStackTopIndex].state;

            /** Record whether message needs to be logged before transitions */
            boolean recordLogMsg = mSm.recordLogRec(mMsg);
            /**
             * Record whether message needs to be logged before we transition and
             * and we won't log special messages SM_INIT_CMD or SM_QUIT_CMD which
             * always set msg.obj to the handler.
             */
            boolean recordLogMsg = mSm.recordLogRec(mMsg) && (msg.obj == mSmHandlerObj);

            while (mDestState != null) {
                if (mDbg) mSm.log("handleMessage: new destination call exit");
            if (mLogRecords.logOnlyTransitions()) {
                /** Record only if there is a transition */
                if (mDestState != null) {
                    mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
                            orgState, mDestState);
                }
            } else if (recordLogMsg) {
                /** Record message */
               mLogRecords.add(mSm, mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
                        orgState, mDestState);
            }

            State destState = mDestState;
            if (destState != null) {
                /**
                 * Save mDestState locally and set to null
                 * to know if enter/exit use transitionTo.
                 * Process the transitions including transitions in the enter/exit methods
                 */
                destState = mDestState;
                mDestState = null;
                while (true) {
                    if (mDbg) mSm.log("handleMessage: new destination call exit/enter");

                    /**
                     * Determine the states to exit and enter and return the
@@ -837,6 +860,16 @@ public class StateMachine {
                     * message queue.
                     */
                    moveDeferredMessageAtFrontOfQueue();

                    if (destState != mDestState) {
                        // A new mDestState so continue looping
                        destState = mDestState;
                    } else {
                        // No change in mDestState so we're done
                        break;
                    }
                }
                mDestState = null;
            }

            /**
@@ -859,21 +892,6 @@ public class StateMachine {
                    mSm.onHalting();
                }
            }

            // Log only if state machine has not quit
            if (mSm != null) {
                if (mLogRecords.logOnlyTransitions()) {
                    /** Record only if there is a transition */
                    if (destState != null) {
                        mLogRecords.add(mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
                                orgState, destState);
                    }
                } else if (recordLogMsg) {
                    /** Record message */
                    mLogRecords.add(mMsg, mSm.getLogRecString(mMsg), msgProcessedState,
                            orgState, destState);
                }
            }
        }

        /**
@@ -1254,20 +1272,6 @@ public class StateMachine {
        mSmHandler.addState(state, parent);
    }

    /**
     * @return current message
     */
    protected final Message getCurrentMessage() {
        return mSmHandler.getCurrentMessage();
    }

    /**
     * @return current state
     */
    protected final IState getCurrentState() {
        return mSmHandler.getCurrentState();
    }

    /**
     * Add a new state to the state machine, parent will be null
     * @param state to add
@@ -1286,6 +1290,26 @@ public class StateMachine {
        mSmHandler.setInitialState(initialState);
    }

    /**
     * @return current message
     */
    protected final Message getCurrentMessage() {
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return null;
        return smh.getCurrentMessage();
    }

    /**
     * @return current state
     */
    protected final IState getCurrentState() {
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return null;
        return smh.getCurrentState();
    }

    /**
     * transition to destination state. Upon returning
     * from processMessage the current state's exit will
@@ -1390,40 +1414,57 @@ public class StateMachine {
     * @return number of log records
     */
    public final int getLogRecSize() {
        return mSmHandler.mLogRecords.size();
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return 0;
        return smh.mLogRecords.size();
    }

    /**
     * @return the total number of records processed
     */
    public final int getLogRecCount() {
        return mSmHandler.mLogRecords.count();
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return 0;
        return smh.mLogRecords.count();
    }

    /**
     * @return a log record
     * @return a log record, or null if index is out of range
     */
    public final LogRec getLogRec(int index) {
        return mSmHandler.mLogRecords.get(index);
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return null;
        return smh.mLogRecords.get(index);
    }

    /**
     * Add the string to LogRecords.
     *
     * @param string
     * @return a copy of LogRecs as a collection
     */
    protected void addLogRec(String string) {
        mSmHandler.mLogRecords.add(null, string, null, null, null);
    public final Collection<LogRec> copyLogRecs() {
        Vector<LogRec> vlr = new Vector<LogRec>();
        SmHandler smh = mSmHandler;
        if (smh != null) {
            for (LogRec lr : smh.mLogRecords.mLogRecVector) {
                vlr.add(lr);
            }
        }
        return vlr;
    }

    /**
     * Add the string and state to LogRecords
     * Add the string to LogRecords.
     *
     * @param string
     * @param state current state
     */
    protected void addLogRec(String string, State state) {
        mSmHandler.mLogRecords.add(null, string, state, null, null);
    protected void addLogRec(String string) {
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;
        smh.mLogRecords.add(this, smh.getCurrentMessage(), string, smh.getCurrentState(),
                smh.mStateStack[smh.mStateStackTopIndex].state, smh.mDestState);
    }

    /**
@@ -1452,168 +1493,217 @@ public class StateMachine {
    }

    /**
     * @return Handler
     * @return Handler, maybe null if state machine has quit.
     */
    public final Handler getHandler() {
        return mSmHandler;
    }

    /**
     * Get a message and set Message.target = this.
     * Get a message and set Message.target state machine handler.
     *
     * Note: The handler can be null if the state machine has quit,
     * which means target will be null and may cause a AndroidRuntimeException
     * in MessageQueue#enqueMessage if sent directly or if sent using
     * StateMachine#sendMessage the message will just be ignored.
     *
     * @return message or null if SM has quit
     * @return  A Message object from the global pool
     */
    public final Message obtainMessage()
    {
        if (mSmHandler == null) return null;

        return Message.obtain(mSmHandler);
    }

    /**
     * Get a message and set Message.target = this and what
     * Get a message and set Message.target state machine handler, what.
     *
     * Note: The handler can be null if the state machine has quit,
     * which means target will be null and may cause a AndroidRuntimeException
     * in MessageQueue#enqueMessage if sent directly or if sent using
     * StateMachine#sendMessage the message will just be ignored.
     *
     * @param what is the assigned to Message.what.
     * @return message or null if SM has quit
     * @return  A Message object from the global pool
     */
    public final Message obtainMessage(int what) {
        if (mSmHandler == null) return null;

        return Message.obtain(mSmHandler, what);
    }

    /**
     * Get a message and set Message.target = this,
     * Get a message and set Message.target state machine handler,
     * what and obj.
     *
     * Note: The handler can be null if the state machine has quit,
     * which means target will be null and may cause a AndroidRuntimeException
     * in MessageQueue#enqueMessage if sent directly or if sent using
     * StateMachine#sendMessage the message will just be ignored.
     *
     * @param what is the assigned to Message.what.
     * @param obj is assigned to Message.obj.
     * @return message or null if SM has quit
     * @return  A Message object from the global pool
     */
    public final Message obtainMessage(int what, Object obj)
    {
        if (mSmHandler == null) return null;

        return Message.obtain(mSmHandler, what, obj);
    }

    /**
     * Get a message and set Message.target = this,
     * Get a message and set Message.target state machine handler,
     * what, arg1 and arg2
     *
     * Note: The handler can be null if the state machine has quit,
     * which means target will be null and may cause a AndroidRuntimeException
     * in MessageQueue#enqueMessage if sent directly or if sent using
     * StateMachine#sendMessage the message will just be ignored.
     *
     * @param what  is assigned to Message.what
     * @param arg1  is assigned to Message.arg1
     * @param arg2  is assigned to Message.arg2
     * @return  A Message object from the global pool or null if
     *          SM has quit
     * @return  A Message object from the global pool
     */
    public final Message obtainMessage(int what, int arg1, int arg2)
    {
        if (mSmHandler == null) return null;

        return Message.obtain(mSmHandler, what, arg1, arg2);
    }

    /**
     * Get a message and set Message.target = this,
     * Get a message and set Message.target state machine handler,
     * what, arg1, arg2 and obj
     *
     * Note: The handler can be null if the state machine has quit,
     * which means target will be null and may cause a AndroidRuntimeException
     * in MessageQueue#enqueMessage if sent directly or if sent using
     * StateMachine#sendMessage the message will just be ignored.
     *
     * @param what  is assigned to Message.what
     * @param arg1  is assigned to Message.arg1
     * @param arg2  is assigned to Message.arg2
     * @param obj is assigned to Message.obj
     * @return  A Message object from the global pool or null if
     *          SM has quit
     * @return  A Message object from the global pool
     */
    public final Message obtainMessage(int what, int arg1, int arg2, Object obj)
    {
        if (mSmHandler == null) return null;

        return Message.obtain(mSmHandler, what, arg1, arg2, obj);
    }

    /**
     * Enqueue a message to this state machine.
     *
     * Message is ignored if state machine has quit.
     */
    public final void sendMessage(int what) {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.sendMessage(obtainMessage(what));
        smh.sendMessage(obtainMessage(what));
    }

    /**
     * Enqueue a message to this state machine.
     *
     * Message is ignored if state machine has quit.
     */
    public final void sendMessage(int what, Object obj) {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.sendMessage(obtainMessage(what,obj));
        smh.sendMessage(obtainMessage(what,obj));
    }

    /**
     * Enqueue a message to this state machine.
     *
     * Message is ignored if state machine has quit.
     */
    public final void sendMessage(Message msg) {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.sendMessage(msg);
        smh.sendMessage(msg);
    }

    /**
     * Enqueue a message to this state machine after a delay.
     *
     * Message is ignored if state machine has quit.
     */
    public final void sendMessageDelayed(int what, long delayMillis) {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.sendMessageDelayed(obtainMessage(what), delayMillis);
        smh.sendMessageDelayed(obtainMessage(what), delayMillis);
    }

    /**
     * Enqueue a message to this state machine after a delay.
     *
     * Message is ignored if state machine has quit.
     */
    public final void sendMessageDelayed(int what, Object obj, long delayMillis) {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
        smh.sendMessageDelayed(obtainMessage(what, obj), delayMillis);
    }

    /**
     * Enqueue a message to this state machine after a delay.
     *
     * Message is ignored if state machine has quit.
     */
    public final void sendMessageDelayed(Message msg, long delayMillis) {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.sendMessageDelayed(msg, delayMillis);
        smh.sendMessageDelayed(msg, delayMillis);
    }

    /**
     * Enqueue a message to the front of the queue for this state machine.
     * Protected, may only be called by instances of StateMachine.
     *
     * Message is ignored if state machine has quit.
     */
    protected final void sendMessageAtFrontOfQueue(int what, Object obj) {
        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(obtainMessage(what, obj));
    }

    /**
     * Enqueue a message to the front of the queue for this state machine.
     * Protected, may only be called by instances of StateMachine.
     *
     * Message is ignored if state machine has quit.
     */
    protected final void sendMessageAtFrontOfQueue(int what) {
        mSmHandler.sendMessageAtFrontOfQueue(obtainMessage(what));
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(obtainMessage(what));
    }

    /**
     * Enqueue a message to the front of the queue for this state machine.
     * Protected, may only be called by instances of StateMachine.
     *
     * Message is ignored if state machine has quit.
     */
    protected final void sendMessageAtFrontOfQueue(Message msg) {
        mSmHandler.sendMessageAtFrontOfQueue(msg);
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.sendMessageAtFrontOfQueue(msg);
    }

    /**
@@ -1621,7 +1711,23 @@ public class StateMachine {
     * Protected, may only be called by instances of StateMachine.
     */
    protected final void removeMessages(int what) {
        mSmHandler.removeMessages(what);
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        smh.removeMessages(what);
    }

    /**
     * Validate that the message was sent by
     * {@link StateMachine#quit} or {@link StateMachine#quitNow}.
     * */
    protected final boolean isQuit(Message msg) {
        // mSmHandler can be null if the state machine has quit.
        SmHandler smh = mSmHandler;
        if (smh == null) return msg.what == SM_QUIT_CMD;

        return smh.isQuit(msg);
    }

    /**
@@ -1629,9 +1735,10 @@ public class StateMachine {
     */
    protected final void quit() {
        // mSmHandler can be null if the state machine is already stopped.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.quit();
        smh.quit();
    }

    /**
@@ -1639,9 +1746,10 @@ public class StateMachine {
     */
    protected final void quitNow() {
        // mSmHandler can be null if the state machine is already stopped.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.quitNow();
        smh.quitNow();
    }

    /**
@@ -1649,9 +1757,10 @@ public class StateMachine {
     */
    public boolean isDbg() {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return false;
        SmHandler smh = mSmHandler;
        if (smh == null) return false;

        return mSmHandler.isDbg();
        return smh.isDbg();
    }

    /**
@@ -1661,9 +1770,10 @@ public class StateMachine {
     */
    public void setDbg(boolean dbg) {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        mSmHandler.setDbg(dbg);
        smh.setDbg(dbg);
    }

    /**
@@ -1671,10 +1781,11 @@ public class StateMachine {
     */
    public void start() {
        // mSmHandler can be null if the state machine has quit.
        if (mSmHandler == null) return;
        SmHandler smh = mSmHandler;
        if (smh == null) return;

        /** Send the complete construction message */
        mSmHandler.completeConstruction();
        smh.completeConstruction();
    }

    /**
@@ -1688,7 +1799,7 @@ public class StateMachine {
        pw.println(getName() + ":");
        pw.println(" total records=" + getLogRecCount());
        for (int i=0; i < getLogRecSize(); i++) {
            pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString(this));
            pw.printf(" rec[%d]: %s\n", i, getLogRec(i).toString());
            pw.flush();
        }
        pw.println("curState=" + getCurrentState().getName());
+313 −281

File changed.

Preview size limit exceeded, changes collapsed.