Merge "SyncSM04: implement processMessage function" into main

This commit is contained in:
Mark Chien
2023-09-20 02:36:05 +00:00
committed by Gerrit Code Review

View File

@@ -18,12 +18,14 @@ package com.android.networkstack.tethering.util;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.os.Message;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.Log; import android.util.Log;
import com.android.internal.util.State; import com.android.internal.util.State;
import java.util.ArrayDeque;
import java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
import java.util.Set; import java.util.Set;
@@ -48,6 +50,14 @@ public class SyncStateMachine {
// mDestState only be null before state machine starts and must only be touched on mMyThread. // mDestState only be null before state machine starts and must only be touched on mMyThread.
@Nullable private State mCurrentState; @Nullable private State mCurrentState;
@Nullable private State mDestState; @Nullable private State mDestState;
private final ArrayDeque<Message> mSelfMsgQueue = new ArrayDeque<Message>();
// MIN_VALUE means not currently processing any message.
private int mCurrentlyProcessing = Integer.MIN_VALUE;
// Indicates whether automaton can send self message. Self messages can only be sent by
// automaton from State#enter, State#exit, or State#processMessage. Calling from outside
// of State is not allowed.
private boolean mSelfMsgAllowed = false;
/** /**
* A information class about a state and its parent. Used to maintain the state hierarchy. * A information class about a state and its parent. Used to maintain the state hierarchy.
@@ -141,16 +151,87 @@ public class SyncStateMachine {
ensureExistingState(initialState); ensureExistingState(initialState);
mDestState = initialState; mDestState = initialState;
mSelfMsgAllowed = true;
performTransitions(); performTransitions();
mSelfMsgAllowed = false;
// If sendSelfMessage was called inside initialState#enter(), mSelfMsgQueue must be
// processed.
maybeProcessSelfMessageQueue();
} }
/** /**
* Process the message synchronously then perform state transition. * Process the message synchronously then perform state transition. This method is used
* externally to the automaton to request that the automaton process the given message.
* The message is processed sequentially, so calling this method recursively is not permitted.
* In other words, using this method inside State#enter, State#exit, or State#processMessage
* is incorrect and will result in an IllegalStateException.
*/ */
public final void processMessage(int what, int arg1, int arg2, @Nullable Object obj) { public final void processMessage(int what, int arg1, int arg2, @Nullable Object obj) {
ensureCorrectThread(); ensureCorrectThread();
if (mCurrentlyProcessing != Integer.MIN_VALUE) {
throw new IllegalStateException("Message(" + mCurrentlyProcessing
+ ") is still being processed");
}
// mCurrentlyProcessing tracks the external message request and it prevents this method to
// be called recursively. Once this message is processed and the transitions have been
// performed, the automaton will process the self message queue. The messages in the self
// message queue are added from within the automaton during processing external message.
// mCurrentlyProcessing is still the original external one and it will not prevent self
// messages from being processed.
mCurrentlyProcessing = what;
final Message msg = Message.obtain(null, what, arg1, arg2, obj);
currentStateProcessMessageThenPerformTransitions(msg);
msg.recycle();
maybeProcessSelfMessageQueue();
mCurrentlyProcessing = Integer.MIN_VALUE;
}
private void maybeProcessSelfMessageQueue() {
while (!mSelfMsgQueue.isEmpty()) {
currentStateProcessMessageThenPerformTransitions(mSelfMsgQueue.poll());
}
}
private void currentStateProcessMessageThenPerformTransitions(@NonNull final Message msg) {
mSelfMsgAllowed = true;
StateInfo consideredState = mStateInfo.get(mCurrentState);
while (null != consideredState) {
// Ideally this should compare with IState.HANDLED, but it is not public field so just
// checking whether the return value is true (IState.HANDLED = true).
if (consideredState.state.processMessage(msg)) {
if (mDbg) {
Log.d(mName, "State " + consideredState.state
+ " processed message " + msg.what);
}
break;
}
consideredState = mStateInfo.get(consideredState.parent);
}
if (null == consideredState) {
Log.wtf(mName, "Message " + msg.what + " was not handled");
}
performTransitions(); performTransitions();
mSelfMsgAllowed = false;
}
/**
* Send self message during state transition.
*
* Must only be used inside State processMessage, enter or exit. The typical use case is
* something wrong happens during state transition, sending an error message which would be
* handled after finishing current state transitions.
*/
public final void sendSelfMessage(int what, int arg1, int arg2, Object obj) {
if (!mSelfMsgAllowed) {
throw new IllegalStateException("sendSelfMessage can only be called inside "
+ "State#enter, State#exit or State#processMessage");
}
mSelfMsgQueue.add(Message.obtain(null, what, arg1, arg2, obj));
} }
/** /**