一.状态机相关的类和数据结构

二.StaStateMachine的创建和初始化流程

ErrCode StaService::InitStaService(const std::vector<StaServiceCallback> &callbacks)
{

    // 创建StaStateMachine
    pStaStateMachine = new (std::nothrow) StaStateMachine(m_instId);

    // 初始化StaStateMachine
    pStaStateMachine->InitStaStateMachine();
}

1.StaStateMachine的创建

StaStateMachine::StaStateMachine(int instId)
    : StateMachine("StaStateMachine")
{
    m_instId = instId;
}

基类StaStateMachine构造函数执行:

StateMachine::StateMachine(const std::string &name)
  : pStateMachineHandler(nullptr), mStateName(name)
{}

2.StaStateMachine的初始化

ErrCode StaStateMachine::InitStaStateMachine()
{
    InitialStateMachine("StaStateMachine"); // 基类接口,创建StateMachineHandler
    InitStaStates(); // 这个逻辑比较简单,就是new 各个状态
    BuildStateTree(); // 这个逻辑也很简单,就是构建状态树图
    SetFirstState(pClosedState); // 设置pClosedState为第一个状态
    StartStateMachine();// 开启状态机!
    return WIFI_OPT_SUCCESS;
}

1.调用基类的InitialStateMachine创建StateMachineHandler

bool StateMachine::InitialStateMachine(const std::string &name) // 这里的name = "StaStateMachine"
{
    pStateMachineHandler = new (std::nothrow) StateMachineHandler(this);
    pStateMachineHandler->InitialSmHandler(name)
    return true;
}

bool StateMachineHandler::InitialSmHandler(const std::string &name)
{
    InitialHandler(name);// 调用基类Handler::InitialHandler
    return true;
}

bool Handler::InitialHandler(const std::string &name)
{
    pMyTaskQueue = std::make_unique<WifiEventHandler>(name); // 创建事件执行任务队列,可以理解为一个线程负责不断处理消息!
    mThreadName = name;
    return true; 
}

2. 创建各个状态

ErrCode StaStateMachine::InitStaStates()
{
    pClosedState = new (std::nothrow) ClosedState(this);
    pInitState = new (std::nothrow) InitState(this);
    pLinkState = new (std::nothrow) LinkState(this);
    pSeparatedState = new (std::nothrow) SeparatedState(this);
    pApLinkingState = new (std::nothrow) ApLinkingState(this);
    pApLinkedState = new (std::nothrow) ApLinkedState(this);
    pGetIpState = new (std::nothrow) GetIpState(this);
    pLinkedState = new (std::nothrow) LinkedState(this);
    pApRoamingState = new (std::nothrow) ApRoamingState(this);
    pApReConnectState = new (std::nothrow) ApReconnectState(this);
    pDhcpResultNotify = new (std::nothrow) DhcpResultNotify(this);
    return WIFI_OPT_SUCCESS;
}
 

3.构建状态树图

void StaStateMachine::BuildStateTree()
{
    StatePlus(pClosedState, nullptr); //father state to handle enable/disable
    StatePlus(pInitState, pClosedState); //father state to handle common event
    StatePlus(pLinkState, pInitState);  //father state to handle link
    StatePlus(pSeparatedState, pInitState); //disconnect state
    StatePlus(pApLinkingState, pLinkState); //L2 connecting
    StatePlus(pApLinkedState, pLinkState); //L2 connected
    StatePlus(pGetIpState, pApLinkedState); //L3 connecting to get ip
    StatePlus(pLinkedState, pApLinkedState); //L3 connected
    StatePlus(pApRoamingState, pApLinkedState); //roaming state
    StatePlus(pApReConnectState, pApLinkedState); //reconnect state
}

 构建出的状态树图如下:

4.设置第一个状态

调用基类StateMachine::SetFirstState

void StateMachine::SetFirstState(State *firstState)
{
    pStateMachineHandler->SetFirstState(firstState);
}

void StateMachineHandler::SetFirstState(State *firstState)
{
    pFirstState = firstState;
}

5.开启状态机---(最复杂和重要,所有状态机都一样的流程)

void StateMachine::StartStateMachine()
{
    pStateMachineHandler->BuildTreeComplete();
}

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;
    }

   // 根据前面 3.构建状态树图可以看出,这里的 maxDepth的值是5!
    mStateVector.resize(maxDepth);
    mSequenceStateVector.resize(maxDepth);
    BuildStateInitVector();

    // 发一条内部启动消息,用来真正进入初始状态(对 Sta 就是调 ClosedState::GoInState())。
    MessageExecutedAtTime(pStateMachine->CreateMessage(SM_INIT_CMD), 0);
    return;
}

此时mStateInfoMap 完整内容(10 项):构建状态树图之后!

 


void StateMachineHandler::BuildStateInitVector()
{

    // 1).必须先 SetFirstState
    if (pFirstState == nullptr) {
        return;
    }

     // 2) 用初始状态名字在 map 里找到 StateInfo
    StateInfoMap::iterator it = mStateInfoMap.find(pFirstState->GetStateName());
    StateInfo *startStateInfo = nullptr;
    if (it != mStateInfoMap.end()) {
        startStateInfo = it->second;
    }

    // 3) 从初始状态沿 upper 往上爬,放进 mSequenceStateVector
    //    顺序是:叶子 → ... → 根(和切换时 BuildSequenceStateVector 一样)
    for (mSequenceStateVectorCount = 0; startStateInfo != nullptr; mSequenceStateVectorCount++) {
        mSequenceStateVector[mSequenceStateVectorCount] = startStateInfo;
        startStateInfo = startStateInfo->upperStateInfo;
    }

    // 4) 清空活动栈顶,再倒序拷进 mStateVector(变成 根 → 叶子)
    mStateVectorTopIndex = -1;
    MoveSequenceToStateVector();
}

BuildStateInitVector 的作用:在真正 GoInState 之前,先把“初始活动路径”填进 mStateVector(根 → 初始叶子),让后面的 SM_INIT_CMD 知道要从哪一段开始 ENTER。

对 Sta:SetFirstState(pClosedState) 后,初始路径只有一层 —— [ClosedState]。

 

四.关键流程讲解

1.消息的处理流程

ExecuteMessage 是每一条消息的统一入口。启动完成后,普通业务消息都走同一套骨架;有没有切状态,差别只在最后的 PerformSwitchState 是否真干活。

void StateMachineHandler::ExecuteMessage(InternalMessagePtr msg)
{
    if (msg == nullptr || mQuitFlag) {
        return;
    }

    pCurrentMsg = msg;

    State *msgProcessedState = nullptr;
    if (mBuildCompleteFlag) {
        msgProcessedState = ExecuteTreeStateMsg(msg);  // 普通消息统一走这里!派发并处理
    } else if (!mBuildCompleteFlag && msg->GetMessageName() == SM_INIT_CMD) { // 处理SM_INIT_CMD消息
        mBuildCompleteFlag = true;
        CallTreeStateEnters(0);
    }

    if (pStateMachine != nullptr) {
        PerformSwitchState(msgProcessedState, msg); // 执行状态切换动作!
    }
}

        State *StateMachineHandler::ExecuteTreeStateMsg(InternalMessagePtr msg)
        {
            if (msg == nullptr) {
                return nullptr;
            }
            // 当前叶子    
            StateInfo *curStateInfo = mStateVector[mStateVectorTopIndex];
            if (curStateInfo == nullptr) {
                return nullptr;
            }

            /* static const bool EXECUTED = true;
             * static const bool NOT_EXECUTED = false;
             * ExecuteStateMsg若执行了改消息就返回 EXECUTED(true), 若没有处理改消息就返回NOT_EXECUTED(false)
             */
            while (curStateInfo->state && (!curStateInfo->state->ExecuteStateMsg(msg))) {
                curStateInfo = curStateInfo->upperStateInfo; // 冒泡
                if (curStateInfo == nullptr) {
                    pStateMachine->NotExecutedMessage(msg); // 这个消息没有任何状态处理,这里也没有什么业务逻辑,就是打印一条debug信息!
                    break;
                }
            }

            return (curStateInfo != nullptr) ? curStateInfo->state : nullptr;
        }

        /* CallTreeStateExits 是状态切换时的**“退出旧状态栈”函数:
         * 从当前最深(叶子)状态开始,自下而上依次调用 GoOutState(),直到遇到与目标状态共享的公共祖先为止;
         * 公共祖先及其更上层的状态不会被退出**。    
         
         * 逻辑很紧凑,核心就三件事:
         *     循环条件:栈顶索引 >= 0,且栈顶状态 不等于 commonStateInfo
         *     每次迭代:对栈顶状态调用 GoOutState(),设 active = false,mStateVectorTopIndex--
         *     停止条件:遇到 commonStateInfo 或栈已空(mStateVectorTopIndex < 0)
         *     注意:不会对 commonStateInfo 本身调用 GoOutState(),它是“停下来的边界”。
         */     
        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)
        {
            // i 从 index 到 top   只 ENTER 路径上这一段(公共祖先以下的新状态)
            for (int i = index; i <= mStateVectorTopIndex; i++) {
                if (index == mStateVectorTopIndex) {
                    mSwitchingStateFlag = false;
                }
                if (mStateVector[i] != nullptr && mStateVector[i]->state != nullptr) {
                    mStateVector[i]->state->GoInState(); // 进入该状态的业务初始化
                    mStateVector[i]->active = true;  // 标记已在活动路径上(之后切换时用来找公共祖先)
                }
            }
            mSwitchingStateFlag = false; // 表示 ENTER 阶段结束
        }

 

2.状态切换逻辑

比如业务调用接口:pStaStateMachine->SwitchState(某一个状态)

void StateMachine::SwitchState(State *targetState)
{
    pStateMachineHandler->SwitchState(targetState);
}

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); // 紧先记录要切换的目标状态
}

然后在StateMachineHandler::ExecuteMessage最后调用PerformSwitchState(msgProcessedState, msg);来执行切换状态的动作:

void StateMachineHandler::PerformSwitchState(State *msgProcessedState, InternalMessagePtr msg)
{
    State *targetState = pTargetState;
    // 本轮没人调 SwitchState → pTargetState == nullptr → 整个函数空过,路径不变。
    if (targetState != nullptr) { 
        while (true) {
             /* BuildSequenceStateVector(targetState)
              *     从目标状态往父爬,把还没 active 的节点放进 mSequenceStateVector(顺序:目标 → … → 靠近公共祖先),直到碰到已经 active 的祖先。
              *         返回值 commonStateInfo = 公共祖先(两边路径都还要留着的那一层)
              *     mSequenceStateVector = 本轮需要 新 ENTER 的那段(尚inactive)
              */
            StateInfo *commonStateInfo = BuildSequenceStateVector(targetState);
            mSwitchingStateFlag = true;

            /* 退出旧状态 (CallTreeStateExits)
             * 从当前叶子沿 mStateVector 往上:
             *  对每个不等于 common 的节点:GoOutState(),active = false,top--
             * 停在公共祖先(公共祖先 不 EXIT)
             */
            CallTreeStateExits(commonStateInfo);


            // 把 mSequenceStateVector 倒序接到当前 mStateVector 后面(父在前、子在后),更新 mStateVectorTopIndex。
            // 返回值 stateListEnteringIndex = 新挂上那一段的起始下标。
            int stateListEnteringIndex = MoveSequenceToStateVector();

            /* 进入新状态 (CallTreeStateEnters)
             * 从该下标到新叶子,依次:
             *     GoInState()
             *     active = true
             */
            CallTreeStateEnters(stateListEnteringIndex);
            
            // 若本轮(或 GoIn 里)有人 DelayMessage,把延迟消息插回队列头,让它们在新状态下尽快再被 ExecuteMessage 处理。
            PlaceDelayedMsgQueueTop();

            if (targetState != pTargetState) {
                targetState = pTargetState;
            } else {
                break;
            }
        }
        pTargetState = nullptr;
    }

    return;
}

        StateInfo *StateMachineHandler::BuildSequenceStateVector(State *targetState)
        {
            // 清空计数,找到目标的 StateInfo
            mSequenceStateVectorCount = 0;
            StateInfoMap::iterator it = mStateInfoMap.find(targetState->GetStateName());
            StateInfo *curStateInfo = nullptr;
            if (it != mStateInfoMap.end()) {
                curStateInfo = it->second;
            }

            if (curStateInfo == nullptr) {
                return nullptr;
            }
            
            /* 从目标往父爬
            规则:
                条件                           含义
                每次先 push 再上移         sequence 里都是还要处理的节点
                父为 nullptr             已经爬到根外,停
                父 active == true        找到公共祖先,父不进 sequence,停
                父 active == false       父也要进,继续爬
            循环结束时:
                mSequenceStateVector:[目标, 父, …](叶子方向 → 根方向,且都是 inactive)
                返回的 curStateInfo:第一个 已经 active 的祖先 = common;若一直爬到根都没有 active,则返回 nullptr
            */
            do {
                mSequenceStateVector[mSequenceStateVectorCount++] = curStateInfo; // 先收录当前节点
                curStateInfo = curStateInfo->upperStateInfo;  // 再走向父
            } while ((curStateInfo != nullptr) && (!curStateInfo->active));

            return curStateInfo;
        }

3.DelayMessage的作用

  作用:把当前正在处理的消息复制一份暂存,等状态切换完成后,再把这份消息插到消息队列头部,让新状态重新处理。

    void StateMachineHandler::DelayMessage(const InternalMessagePtr msg)
    {
        if (msg == nullptr) {
            return;
        }
        // 对原消息做深拷贝(CreateMessage(orig) 会复制 msgName、param1/2、messageObj、body 等)
        InternalMessagePtr newMsg = pStateMachine->CreateMessage(msg);
        // 拷贝放入 mDelayedMessages 数组,不会立刻重新投递
        mDelayedMessages.push_back(newMsg);
        // 原消息msg本轮处理照常结束,之后由消息池回收
        return;
    }

 

附录1:

P2pStateMachine的状态树图:

 

 

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐