* Copyright (C) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <cinttypes>
#include "state_machine.h"
#include "wifi_log.h"
#undef LOG_TAG
#define LOG_TAG "OHWIFI_STATE_MACHINE"
namespace OHOS {
namespace Wifi {
static const int SM_INIT_CMD = -2;
StateMachine::StateMachine(const std::string &name) : pStateMachineHandler(nullptr), mStateName(name)
{}
StateMachine::~StateMachine()
{
LOGD("StateMachine::~StateMachine");
if (pStateMachineHandler != nullptr) {
delete pStateMachineHandler;
pStateMachineHandler = nullptr;
}
}
bool StateMachine::InitialStateMachine(const std::string &name)
{
LOGI("InitialStateMachine\n");
pStateMachineHandler = new (std::nothrow) StateMachineHandler(this);
if (pStateMachineHandler == nullptr) {
LOGE("pStateMachineHandler alloc failed.\n");
return false;
}
if (!pStateMachineHandler->InitialSmHandler(name)) {
LOGE("InitialStateMachineHandler failed.\n");
return false;
}
return true;
}
void StateMachine::StartStateMachine()
{
if (pStateMachineHandler == nullptr) {
LOGE("StartStateMachine failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->BuildTreeComplete();
return;
}
void StateMachine::SetHandler(StateMachineHandler *handler)
{
pStateMachineHandler = handler;
}
void StateMachine::NotExecutedMessage(const InternalMessagePtr msg)
{
if (msg == nullptr) {
return;
}
LOGD("msg not handled msg:%{public}d", msg->GetMessageName());
}
void StateMachine::StatePlus(State *state, State *upper)
{
if (pStateMachineHandler == nullptr) {
LOGE("StatePlus failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->StatePlus(state, upper);
}
void StateMachine::StateDelete(State *state)
{
if (pStateMachineHandler == nullptr) {
LOGE("StateDelete failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->StateDelete(state);
}
void StateMachine::SetFirstState(State *firstState)
{
if (pStateMachineHandler == nullptr) {
LOGE("SetFirstState failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->SetFirstState(firstState);
}
void StateMachine::SwitchState(State *targetState)
{
if (pStateMachineHandler == nullptr) {
LOGE("SwitchState failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->SwitchState(targetState);
}
void StateMachine::DelayMessage(const InternalMessagePtr msg)
{
if (pStateMachineHandler == nullptr) {
LOGE("DelayMessage failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->DelayMessage(msg);
}
void StateMachine::StopHandlerThread()
{
if (pStateMachineHandler == nullptr) {
LOGE("StopHandlerThread failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->StopHandlerThread();
}
InternalMessagePtr StateMachine::CreateMessage()
{
return MessageManage::GetInstance().CreateMessage();
}
InternalMessagePtr StateMachine::CreateMessage(const InternalMessagePtr orig)
{
if (orig == nullptr) {
return nullptr;
}
return MessageManage::GetInstance().CreateMessage(orig);
}
InternalMessagePtr StateMachine::CreateMessage(int msgName)
{
return MessageManage::GetInstance().CreateMessage(msgName);
}
InternalMessagePtr StateMachine::CreateMessage(int msgName, int param1)
{
return MessageManage::GetInstance().CreateMessage(msgName, param1, 0);
}
InternalMessagePtr StateMachine::CreateMessage(int msgName, int param1, int param2)
{
return MessageManage::GetInstance().CreateMessage(msgName, param1, param2);
}
InternalMessagePtr StateMachine::CreateMessage(int msgName, const std::any &messageObj)
{
return MessageManage::GetInstance().CreateMessage(msgName, messageObj);
}
InternalMessagePtr StateMachine::CreateMessage(int msgName, int param1, int param2, const std::any &messageObj)
{
return MessageManage::GetInstance().CreateMessage(msgName, param1, param2, messageObj);
}
void StateMachine::SendMessage(int msgName)
{
if (pStateMachineHandler == nullptr) {
LOGE("SendMessage failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->SendMessage(CreateMessage(msgName));
return;
}
void StateMachine::SendMessage(int msgName, int param1)
{
if (pStateMachineHandler == nullptr) {
LOGE("SendMessage failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->SendMessage(CreateMessage(msgName, param1));
return;
}
void StateMachine::SendMessage(int msgName, int param1, int param2)
{
if (pStateMachineHandler == nullptr) {
LOGE("SendMessage failed, pStateMachineHandler is nullptr!");
return;
}
pStateMachineHandler->SendMessage(CreateMessage(msgName, param1, param2));
return;
}
void StateMachine::SendMessage(InternalMessagePtr msg)
{
if (msg == nullptr) {
return;
}
if (pStateMachineHandler != nullptr) {
pStateMachineHandler->SendMessage(msg);
}
return;
}
void StateMachine::SendMessage(int msgName, const std::any &messageObj)
{
pStateMachineHandler->SendMessage(CreateMessage(msgName, messageObj));
return;
}
void StateMachine::SendMessage(int msgName, int param1, int param2, const std::any &messageObj)
{
pStateMachineHandler->SendMessage(CreateMessage(msgName, param1, param2, messageObj));
return;
}
void StateMachine::MessageExecutedLater(int msgName, int64_t delayTimeMs, MsgLogLevel logLevel)
{
InternalMessagePtr msg = CreateMessage(msgName);
if (msg == NULL) {
return;
}
msg->msgLogLevel_ = logLevel;
pStateMachineHandler->MessageExecutedLater(msg, delayTimeMs);
return;
}
void StateMachine::MessageExecutedLater(int msgName, int param1, int64_t delayTimeMs)
{
pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, param1), delayTimeMs);
return;
}
void StateMachine::MessageExecutedLater(int msgName, int param1, int param2, int64_t delayTimeMs)
{
pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, param1, param2), delayTimeMs);
return;
}
void StateMachine::MessageExecutedLater(InternalMessagePtr msg, int64_t delayTimeMs)
{
pStateMachineHandler->MessageExecutedLater(msg, delayTimeMs);
return;
}
void StateMachine::MessageExecutedLater(int msgName, const std::any &messageObj, int64_t delayTimeMs)
{
pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, messageObj), delayTimeMs);
return;
}
void StateMachine::MessageExecutedLater(
int msgName, int param1, int param2, const std::any &messageObj, int64_t delayTimeMs)
{
pStateMachineHandler->MessageExecutedLater(CreateMessage(msgName, param1, param2, messageObj), delayTimeMs);
return;
}
void StateMachine::SendMessageAtFrontOfQueue(int msgName, int param1)
{
pStateMachineHandler->PlaceMessageTopOfQueue(CreateMessage(msgName, param1));
return;
}
void StateMachine::StartTimer(int timerName, int64_t interval, MsgLogLevel logLevel)
{
LOGD("Enter StartTimer, timerName is %{public}d, interval is %" PRId64 ".", timerName, interval);
MessageExecutedLater(timerName, interval, logLevel);
return;
}
void StateMachine::StopTimer(int timerName)
{
LOGD("Enter StopTimer, timerName is %{public}d.", timerName);
if (pStateMachineHandler != nullptr) {
pStateMachineHandler->DeleteMessageFromQueue(timerName);
}
return;
}
std::string StateMachine::GetCurStateName()
{
LOGD("GetCurStateName");
if (pStateMachineHandler == nullptr) {
LOGE("GetCurStateName failed, pStateMachineHandler is nullptr!");
return "";
}
return pStateMachineHandler->GetCurStateName();
}
StateMachineHandler::StateMachineHandler(StateMachine *pStateMgr)
{
mStateInfoMap.clear();
mStateVector.clear();
mStateVectorTopIndex = -1;
mSequenceStateVector.clear();
mSequenceStateVectorCount = 0;
mDelayedMessages.clear();
pStateMachine = pStateMgr;
pFirstState = nullptr;
pTargetState = nullptr;
mQuitFlag = false;
mBuildCompleteFlag = false;
mSwitchingStateFlag = false;
pCurrentMsg = nullptr;
}
StateMachineHandler::~StateMachineHandler()
{
LOGI("~StateMachineHandler");
StopHandlerThread();
ReleaseDelayedMessages();
ClearWhenQuit();
return;
}
bool StateMachineHandler::InitialSmHandler(const std::string &name)
{
if (!InitialHandler(name)) {
LOGE("InitialHandler failed.");
return false;
}
return true;
}
StateInfo *StateMachineHandler::StatePlus(State *state, State *upper)
{
LOGD("Enter StateMachineHandler::StatePlus function.");
StateInfo *upperStateInfo = nullptr;
StateInfoMap::iterator it = mStateInfoMap.begin();
if (upper != nullptr) {
it = mStateInfoMap.find(upper->GetStateName());
if (it != mStateInfoMap.end()) {
upperStateInfo = it->second;
}
if (upperStateInfo == nullptr) {
LOGD("upperStateInfo is null, add upper first. upper->GetStateName():%{public}s",
upper->GetStateName().c_str());
StatePlus(upper, nullptr);
} else {
LOGD("upperStateInfo is not null, go on.");
}
}
StateInfo *stateInfo = nullptr;
if (state == nullptr) {
LOGE("state is null");
return nullptr;
} else {
it = mStateInfoMap.find(state->GetStateName());
}
if (it != mStateInfoMap.end()) {
stateInfo = it->second;
}
if (stateInfo == nullptr) {
stateInfo = new (std::nothrow) StateInfo();
if (stateInfo == nullptr) {
LOGE("failed to new StateInfo!");
return nullptr;
}
mStateInfoMap.insert(StateInfoMap::value_type(state->GetStateName(), stateInfo));
}
if (stateInfo->upperStateInfo != nullptr && stateInfo->upperStateInfo != upperStateInfo) {
LOGE("The same state cannot be added to two different hierarchies!");
}
stateInfo->state = state;
stateInfo->upperStateInfo = upperStateInfo;
stateInfo->active = false;
LOGD("successfully added a new state!");
return stateInfo;
}
void StateMachineHandler::StateDelete(State *state)
{
StateInfoMap::iterator it = mStateInfoMap.find(state->GetStateName());
StateInfo *stateInfo = nullptr;
if (it != mStateInfoMap.end()) {
stateInfo = it->second;
}
if (stateInfo == nullptr || stateInfo->active) {
return;
}
it = mStateInfoMap.begin();
while (it != mStateInfoMap.end()) {
if (it->second->upperStateInfo == stateInfo) {
return;
}
++it;
}
it = mStateInfoMap.find(state->GetStateName());
if (it != mStateInfoMap.end()) {
delete it->second;
it->second = nullptr;
mStateInfoMap.erase(it);
}
}
void StateMachineHandler::SetFirstState(State *firstState)
{
pFirstState = firstState;
}
void StateMachineHandler::BuildTreeComplete()
{
int maxDepth = 0;
StateInfoMap::iterator it = mStateInfoMap.begin();
while (it != mStateInfoMap.end()) {
int depth = 0;
StateInfo *tempStateInfo = it->second;
while (tempStateInfo != nullptr) {
depth++;
tempStateInfo = tempStateInfo->upperStateInfo;
}
if (maxDepth < depth) {
maxDepth = depth;
}
++it;
}
LOGD("StateMachineHandler::BuildTreeComplete, maxDepth:%{public}d", maxDepth);
mStateVector.resize(maxDepth);
mSequenceStateVector.resize(maxDepth);
BuildStateInitVector();
MessageExecutedAtTime(pStateMachine->CreateMessage(SM_INIT_CMD), 0);
return;
}
void StateMachineHandler::BuildStateInitVector()
{
LOGD("StateMachineHandler::BuildStateInitVector");
if (pFirstState == nullptr) {
LOGE("StateMachineHandler::BuildStateInitVector please set initial state first!");
return;
}
StateInfoMap::iterator it = mStateInfoMap.find(pFirstState->GetStateName());
StateInfo *startStateInfo = nullptr;
if (it != mStateInfoMap.end()) {
startStateInfo = it->second;
}
for (mSequenceStateVectorCount = 0; startStateInfo != nullptr; mSequenceStateVectorCount++) {
mSequenceStateVector[mSequenceStateVectorCount] = startStateInfo;
startStateInfo = startStateInfo->upperStateInfo;
}
mStateVectorTopIndex = -1;
MoveSequenceToStateVector();
}
StateInfo *StateMachineHandler::BuildSequenceStateVector(State *targetState)
{
mSequenceStateVectorCount = 0;
StateInfoMap::iterator it = mStateInfoMap.find(targetState->GetStateName());
StateInfo *curStateInfo = nullptr;
if (it != mStateInfoMap.end()) {
curStateInfo = it->second;
}
if (curStateInfo == nullptr) {
return nullptr;
}
do {
mSequenceStateVector[mSequenceStateVectorCount++] = curStateInfo;
curStateInfo = curStateInfo->upperStateInfo;
} while ((curStateInfo != nullptr) && (!curStateInfo->active));
return curStateInfo;
}
void StateMachineHandler::PlaceDelayedMsgQueueTop()
{
LOGD("Enter StateMachineHandler::PlaceDelayedMsgQueueTop.");
if (mDelayedMessages.size() == 0) {
return;
}
for (int i = mDelayedMessages.size() - 1; i >= 0; i--) {
InternalMessagePtr curMsg = mDelayedMessages[i];
if (curMsg == nullptr) {
LOGE("StateMachineHandler::PlaceDelayedMsgQueueTop: curMsg is null.");
continue;
}
PlaceMessageTopOfQueue(curMsg);
}
mDelayedMessages.clear();
return;
}
void StateMachineHandler::ReleaseDelayedMessages()
{
if (mDelayedMessages.size() == 0) {
return;
}
for (int i = mDelayedMessages.size() - 1; i >= 0; i--) {
InternalMessagePtr curMsg = mDelayedMessages[i];
if (curMsg != nullptr) {
curMsg = nullptr;
}
}
mDelayedMessages.clear();
return;
}
int StateMachineHandler::MoveSequenceToStateVector()
{
LOGD("StateMachineHandler::MoveSequenceToStateVector mSequenceStateVectorCount:%{public}d",
mSequenceStateVectorCount);
int newIndex = mStateVectorTopIndex + 1;
int i = mSequenceStateVectorCount - 1;
int j = newIndex;
while (i >= 0) {
mStateVector[j] = mSequenceStateVector[i];
j += 1;
i -= 1;
}
mStateVectorTopIndex = j - 1;
return newIndex;
}
void StateMachineHandler::SwitchState(State *targetState)
{
if (targetState == nullptr) {
LOGE("targetState is null.");
return;
}
LOGE("SwitchState, Switch to targetState: %{public}s.", targetState->GetStateName().c_str());
pTargetState = static_cast<State *>(targetState);
}
void StateMachineHandler::ClearWhenQuit()
{
pStateMachine->SetHandler(nullptr);
pStateMachine = nullptr;
pCurrentMsg = nullptr;
mStateVector.clear();
mSequenceStateVector.clear();
mDelayedMessages.clear();
pFirstState = nullptr;
pTargetState = nullptr;
mQuitFlag = true;
StateInfoMap::iterator it = mStateInfoMap.begin();
while (it != mStateInfoMap.end()) {
delete it->second;
it->second = nullptr;
it = mStateInfoMap.erase(it);
}
mStateInfoMap.clear();
}
void StateMachineHandler::PerformSwitchState(State *msgProcessedState, InternalMessagePtr msg)
{
if (msgProcessedState == nullptr || msg == nullptr) {
LOGD("pointer is null.");
}
State *targetState = pTargetState;
if (targetState != nullptr) {
if (pFirstState != nullptr) {
LOGD("StateMachineHandler::PerformSwitchState, Switch %{public}s -->> %{public}s",
pFirstState->GetStateName().c_str(), targetState->GetStateName().c_str());
}
while (true) {
StateInfo *commonStateInfo = BuildSequenceStateVector(targetState);
mSwitchingStateFlag = true;
CallTreeStateExits(commonStateInfo);
int stateListEnteringIndex = MoveSequenceToStateVector();
CallTreeStateEnters(stateListEnteringIndex);
PlaceDelayedMsgQueueTop();
if (targetState != pTargetState) {
targetState = pTargetState;
} else {
break;
}
}
pTargetState = nullptr;
}
return;
}
void StateMachineHandler::ExecuteMessage(InternalMessagePtr msg)
{
if (msg == nullptr) {
return;
}
if (!mQuitFlag) {
if (pStateMachine != nullptr && msg->GetMessageName() != SM_INIT_CMD) {
}
pCurrentMsg = msg;
State *msgProcessedState = nullptr;
if (mBuildCompleteFlag) {
LOGD("StateMachineHandler::ExecuteMessage ExecuteTreeStateMsg!");
msgProcessedState = ExecuteTreeStateMsg(msg);
} else if (!mBuildCompleteFlag && msg->GetMessageName() == SM_INIT_CMD) {
LOGD("StateMachineHandler::ExecuteMessage msg: SM_INIT_CMD");
mBuildCompleteFlag = true;
CallTreeStateEnters(0);
} else {
LOGE("The start method not called!");
}
if (pStateMachine != nullptr) {
PerformSwitchState(msgProcessedState, msg);
}
if (pStateMachine != nullptr && msg->GetMessageName() != SM_INIT_CMD) {
}
}
return;
}
void StateMachineHandler::DelayMessage(const InternalMessagePtr msg)
{
LOGD("Enter StateMachineHandler::DelayMessage.");
if (msg == nullptr) {
return;
}
InternalMessagePtr newMsg = pStateMachine->CreateMessage(msg);
if (newMsg == nullptr) {
LOGE("StateMachineHandler::DelayMessage: newMsg is null.");
return;
}
mDelayedMessages.push_back(newMsg);
return;
}
State *StateMachineHandler::ExecuteTreeStateMsg(InternalMessagePtr msg)
{
LOGD("StateMachineHandler::ExecuteTreeStateMsg mStateVectorTopIndex:%{public}d", mStateVectorTopIndex);
if (msg == nullptr) {
LOGE("ExecuteTreeStateMsg, msg is nullptr.");
return nullptr;
}
StateInfo *curStateInfo = mStateVector[mStateVectorTopIndex];
if (curStateInfo == nullptr) {
LOGE("ExecuteTreeStateMsg, curStateInfo is nullptr.");
return nullptr;
}
while (curStateInfo->state && (!curStateInfo->state->ExecuteStateMsg(msg))) {
curStateInfo = curStateInfo->upperStateInfo;
if (curStateInfo == nullptr) {
pStateMachine->NotExecutedMessage(msg);
break;
}
}
return (curStateInfo != nullptr) ? curStateInfo->state : nullptr;
}
void StateMachineHandler::CallTreeStateExits(StateInfo *commonStateInfo)
{
while ((mStateVectorTopIndex >= 0) && (mStateVector[mStateVectorTopIndex] != commonStateInfo)) {
if (mStateVector[mStateVectorTopIndex] != nullptr) {
State *curState = mStateVector[mStateVectorTopIndex]->state;
if (curState != nullptr) {
curState->GoOutState();
}
mStateVector[mStateVectorTopIndex]->active = false;
}
mStateVectorTopIndex -= 1;
}
}
void StateMachineHandler::CallTreeStateEnters(int index)
{
for (int i = index; i <= mStateVectorTopIndex; i++) {
if (index == mStateVectorTopIndex) {
mSwitchingStateFlag = false;
}
LOGD("StateMachineHandler::CallTreeStateEnters mStateVectorTopIndex:%{public}d, i: %{public}d",
mStateVectorTopIndex,
i);
if (mStateVector[i] != nullptr && mStateVector[i]->state != nullptr) {
mStateVector[i]->state->GoInState();
mStateVector[i]->active = true;
}
}
mSwitchingStateFlag = false;
}
std::string StateMachineHandler::GetCurStateName()
{
if (mStateVectorTopIndex < 0) {
return "";
}
StateInfo *curStateInfo = mStateVector[mStateVectorTopIndex];
if (curStateInfo == nullptr) {
LOGE("StateInfo is null.");
return "";
}
return curStateInfo->state != nullptr ? curStateInfo->state->GetStateName() : "";
}
}
}