OSDN Git Service

Add Log.wtf when transitionTo is used improperly
authorMitchell Wills <mwills@google.com>
Thu, 11 Aug 2016 18:05:03 +0000 (11:05 -0700)
committerMitchell Wills <mwills@google.com>
Thu, 11 Aug 2016 20:54:48 +0000 (13:54 -0700)
Using transitionTo in exit/enter (except in the terminal state) is
documented as undefined behavior and may cause unexpected results.
The current implementation appears to finish the current transition and
then transition to the new target state.

TEST=flash and play with the phone, no sign of immediate WTFs

Change-Id: I38a34b85c43d53c51514339587fc1269a069a454

core/java/com/android/internal/util/StateMachine.java

index f137821..b0d45e1 100644 (file)
@@ -750,6 +750,14 @@ public class StateMachine {
         /** The destination state when transitionTo has been invoked */
         private State mDestState;
 
+        /**
+         * Indicates if a transition is in progress
+         *
+         * This will be true for all calls of State.exit and all calls of State.enter except for the
+         * last enter call for the current destination state.
+         */
+        private boolean mTransitionInProgress = false;
+
         /** The list of deferred messages */
         private ArrayList<Message> mDeferredMessages = new ArrayList<Message>();
 
@@ -862,6 +870,8 @@ public class StateMachine {
                      * invoke the exit methods then the enter methods.
                      */
                     StateInfo commonStateInfo = setupTempStateStackWithStatesToEnter(destState);
+                    // flag is cleared in invokeEnterMethods before entering the target state
+                    mTransitionInProgress = true;
                     invokeExitMethods(commonStateInfo);
                     int stateStackEnteringIndex = moveTempStateStackToStateStack();
                     invokeEnterMethods(stateStackEnteringIndex);
@@ -1017,10 +1027,15 @@ public class StateMachine {
          */
         private final void invokeEnterMethods(int stateStackEnteringIndex) {
             for (int i = stateStackEnteringIndex; i <= mStateStackTopIndex; i++) {
+                if (stateStackEnteringIndex == mStateStackTopIndex) {
+                    // Last enter state for transition
+                    mTransitionInProgress = false;
+                }
                 if (mDbg) mSm.log("invokeEnterMethods: " + mStateStack[i].state.getName());
                 mStateStack[i].state.enter();
                 mStateStack[i].active = true;
             }
+            mTransitionInProgress = false; // ensure flag set to false if no methods called
         }
 
         /**
@@ -1196,6 +1211,10 @@ public class StateMachine {
 
         /** @see StateMachine#transitionTo(IState) */
         private final void transitionTo(IState destState) {
+            if (mTransitionInProgress) {
+                Log.wtf(mSm.mName, "transitionTo called while transition already in progress to " +
+                        mDestState + ", new target state=" + destState);
+            }
             mDestState = (State) destState;
             if (mDbg) mSm.log("transitionTo: destState=" + mDestState.getName());
         }