OpenHarmony-WiFi框架层状态机详解(以StaStateMachine为例)
一.状态机相关的类和数据结构



二.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的状态树图:
更多推荐

所有评论(0)