/* * Copyright (C) 2021 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. */ #ifndef STATE_MACHINE_H #define STATE_MACHINE_H #include #include #include #include #include "cellular_data_event_code.h" #include "inner_event.h" #include "tel_event_handler.h" #include "telephony_log_wrapper.h" namespace OHOS { namespace Telephony { class State : public RefBase { #define PROCESSED true #define NOT_PROCESSED false public: explicit State(std::string &&name) : name_(std::move(name)) {} virtual ~State() = default; virtual void StateBegin() = 0; virtual void StateEnd() = 0; virtual bool StateProcess(const AppExecFwk::InnerEvent::Pointer &event) = 0; void SetParentState(sptr &parent) { parent_ = parent; } std::string GetStateMachineName() const { return name_; } protected: friend class StateMachineEventHandler; std::string name_; sptr parent_; bool isActive_ = false; }; class StateMachineEventHandler : public TelEventHandler { public: explicit StateMachineEventHandler(const std::string &name) : TelEventHandler(name) {} ~StateMachineEventHandler() = default; virtual void SetOriginalState(sptr &originalState) { originalState_ = originalState; } virtual void TransitionTo(sptr &destState) { TELEPHONY_LOGI("State machine transition to %{public}s", destState->name_.c_str()); destState_ = destState; } virtual void Quit() { sptr tmpState = curState_; while (tmpState != nullptr && tmpState->isActive_) { tmpState->StateEnd(); tmpState = tmpState->parent_; isQuit_ = true; } } // Only two-layer StateMachines are supported virtual void ProcessTransitions(const AppExecFwk::InnerEvent::Pointer &event) { if (curState_ != destState_) { TELEPHONY_LOGD("Begin process transitions"); if (curState_ != nullptr) { sptr tmpState = curState_->parent_; while (tmpState != nullptr) { tmpState->StateEnd(); tmpState = tmpState->parent_; } curState_->StateEnd(); } if (destState_ != nullptr) { sptr tmpState = destState_->parent_; while (tmpState != nullptr) { tmpState->StateBegin(); tmpState = tmpState->parent_; } destState_->StateBegin(); } curState_ = destState_; SendDeferredEvent(); } } void DeferEvent(AppExecFwk::InnerEvent::Pointer &&event) { std::lock_guard guard(mtx_); deferEvents_.push_back(std::move(event)); } virtual void ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event) { if (event == nullptr || isQuit_) { TELEPHONY_LOGE("The event parameter is incorrect"); return; } if (event->GetInnerEventId() == CellularDataEventCode::MSG_STATE_MACHINE_QUIT) { TELEPHONY_LOGI("State machine exit"); Quit(); return; } if (event->GetInnerEventId() == CellularDataEventCode::MSG_STATE_MACHINE_INIT) { destState_ = originalState_; InitCmdEnter(originalState_); } ProcessMsg(event); ProcessTransitions(event); } virtual void ProcessMsg(const AppExecFwk::InnerEvent::Pointer &event) { sptr tmpState = curState_; TELEPHONY_LOGD("The event id: %{public}u", event->GetInnerEventId()); while (tmpState != nullptr && !tmpState->StateProcess(event)) { tmpState = tmpState->parent_; } } private: void InitCmdEnter(const sptr &state) { if (state == nullptr) { TELEPHONY_LOGE("registerState_ is null"); return; } if (state->parent_ != nullptr) { InitCmdEnter(state->parent_); } TELEPHONY_LOGI("Initialize entry %{public}s", state->name_.c_str()); state->StateBegin(); curState_ = state; } void SendDeferredEvent() { std::lock_guard guard(mtx_); if (deferEvents_.empty()) { return; } for (size_t i = 0; i < deferEvents_.size(); ++i) { AppExecFwk::InnerEvent::Pointer event = std::move(deferEvents_[i]); SendImmediateEvent(event); } deferEvents_.clear(); } private: sptr originalState_; sptr destState_; sptr curState_; std::vector deferEvents_; std::mutex mtx_; bool isQuit_ = false; }; class StateMachine { public: explicit StateMachine(const std::string &name) { stateMachineEventHandler_ = std::make_shared(name); if (stateMachineEventHandler_ == nullptr) { TELEPHONY_LOGE("stateMachineEventHandler_ is null"); return; } } virtual ~StateMachine() {} void Quit() { AppExecFwk::InnerEvent::Pointer event = AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STATE_MACHINE_QUIT); if (stateMachineEventHandler_ == nullptr) { TELEPHONY_LOGE("stateMachineEventHandler_ is null"); return; } stateMachineEventHandler_->SendImmediateEvent(event); } void Start() { if (stateMachineEventHandler_ == nullptr) { TELEPHONY_LOGE("stateMachineEventHandler_ is null"); return; } AppExecFwk::InnerEvent::Pointer event = AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STATE_MACHINE_INIT); stateMachineEventHandler_->SendImmediateEvent(event); } void SetOriginalState(sptr &originalState) { if (originalState == nullptr) { TELEPHONY_LOGE("originalState is null"); return; } if (stateMachineEventHandler_ == nullptr) { TELEPHONY_LOGE("stateMachineEventHandler_ is null"); return; } stateMachineEventHandler_->SetOriginalState(originalState); } void TransitionTo(sptr &destState) { if (destState == nullptr) { TELEPHONY_LOGE("destState is null"); return; } if (stateMachineEventHandler_ == nullptr) { TELEPHONY_LOGE("stateMachineEventHandler_ is null"); return; } stateMachineEventHandler_->TransitionTo(destState); } void DeferEvent(const AppExecFwk::InnerEvent::Pointer &&event) { if (stateMachineEventHandler_ == nullptr) { TELEPHONY_LOGE("stateMachineEventHandler_ is null"); return; } stateMachineEventHandler_->DeferEvent(std::move(const_cast(event))); } void SendEvent(AppExecFwk::InnerEvent::Pointer &event) { if (stateMachineEventHandler_ == nullptr) { TELEPHONY_LOGE("stateMachineEventHandler_ is null"); return; } if (event == nullptr) { TELEPHONY_LOGE("event is null"); return; } TELEPHONY_LOGD("State machine send event id %{public}u ", event->GetInnerEventId()); stateMachineEventHandler_->SendEvent(event); } protected: std::shared_ptr stateMachineEventHandler_; }; } // namespace Telephony } // namespace OHOS #endif // STATE_MACHINE_H