• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef STATE_MACHINE_H
17 #define STATE_MACHINE_H
18 
19 #include <memory>
20 #include <mutex>
21 #include <utility>
22 #include <vector>
23 
24 #include "event_handler.h"
25 #include "inner_event.h"
26 
27 #include "telephony_log_wrapper.h"
28 
29 #include "cellular_data_event_code.h"
30 
31 namespace OHOS {
32 namespace Telephony {
33 class State : public RefBase {
34 #define PROCESSED true
35 #define NOT_PROCESSED false
36 public:
State(std::string && name)37     explicit State(std::string &&name) : name_(std::move(name)) {}
38     virtual ~State() = default;
39     virtual void StateBegin() = 0;
40     virtual void StateEnd() = 0;
41     virtual bool StateProcess(const AppExecFwk::InnerEvent::Pointer &event) = 0;
42 
SetParentState(sptr<State> & parent)43     void SetParentState(sptr<State> &parent)
44     {
45         parent_ = parent;
46     }
47 
GetStateMachineName()48     std::string GetStateMachineName() const
49     {
50         return name_;
51     }
52 
53 protected:
54     friend class StateMachineEventHandler;
55     std::string name_;
56     sptr<State> parent_;
57     bool isActive_ = false;
58 };
59 
60 class StateMachineEventHandler : public AppExecFwk::EventHandler {
61 public:
StateMachineEventHandler(const std::shared_ptr<AppExecFwk::EventRunner> & runner)62     explicit StateMachineEventHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner)
63         : EventHandler(runner)
64     {}
65     ~StateMachineEventHandler() = default;
66 
SetOriginalState(sptr<State> & originalState)67     virtual void SetOriginalState(sptr<State> &originalState)
68     {
69         originalState_ = originalState;
70     }
71 
TransitionTo(sptr<State> & destState)72     virtual void TransitionTo(sptr<State> &destState)
73     {
74         TELEPHONY_LOGI("State machine transition to %{public}s", destState->name_.c_str());
75         destState_ = destState;
76     }
77 
Quit()78     virtual void Quit()
79     {
80         sptr<State> tmpState = curState_;
81         while (tmpState != nullptr && tmpState->isActive_) {
82             tmpState->StateEnd();
83             tmpState = tmpState->parent_;
84             isQuit_ = true;
85         }
86     }
87 
88     // Only two-layer StateMachines are supported
ProcessTransitions(const AppExecFwk::InnerEvent::Pointer & event)89     virtual void ProcessTransitions(const AppExecFwk::InnerEvent::Pointer &event)
90     {
91         if (curState_ != destState_) {
92             TELEPHONY_LOGI("Begin process transitions");
93             if (curState_ != nullptr) {
94                 sptr<State> tmpState = curState_->parent_;
95                 while (tmpState != nullptr) {
96                     tmpState->StateEnd();
97                     tmpState = tmpState->parent_;
98                 }
99                 curState_->StateEnd();
100             }
101             if (destState_ != nullptr) {
102                 sptr<State> tmpState = destState_->parent_;
103                 while (tmpState != nullptr) {
104                     tmpState->StateBegin();
105                     tmpState = tmpState->parent_;
106                 }
107                 destState_->StateBegin();
108             }
109             curState_ = destState_;
110             SendDeferredEvent();
111         }
112     }
113 
DeferEvent(AppExecFwk::InnerEvent::Pointer && event)114     void DeferEvent(AppExecFwk::InnerEvent::Pointer &&event)
115     {
116         std::lock_guard<std::mutex> guard(mtx_);
117         deferEvents_.push_back(std::move(event));
118     }
119 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)120     virtual void ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
121     {
122         if (event == nullptr || isQuit_) {
123             TELEPHONY_LOGE("The event parameter is incorrect");
124             return;
125         }
126         if (event->GetInnerEventId() == CellularDataEventCode::MSG_STATE_MACHINE_QUIT) {
127             TELEPHONY_LOGI("State machine exit");
128             Quit();
129             return;
130         }
131         if (event->GetInnerEventId() == CellularDataEventCode::MSG_STATE_MACHINE_INIT) {
132             destState_ = originalState_;
133             InitCmdEnter(originalState_);
134         }
135         ProcessMsg(event);
136         ProcessTransitions(event);
137     }
138 
ProcessMsg(const AppExecFwk::InnerEvent::Pointer & event)139     virtual void ProcessMsg(const AppExecFwk::InnerEvent::Pointer &event)
140     {
141         sptr<State> tmpState = curState_;
142         TELEPHONY_LOGI("The event id: %{public}u", event->GetInnerEventId());
143         while (tmpState != nullptr && !tmpState->StateProcess(event)) {
144             tmpState = tmpState->parent_;
145         }
146     }
147 
148 private:
InitCmdEnter(const sptr<State> & state)149     void InitCmdEnter(const sptr<State> &state)
150     {
151         if (state == nullptr) {
152             TELEPHONY_LOGE("registerState_ is null");
153             return;
154         }
155         if (state->parent_ != nullptr) {
156             InitCmdEnter(state->parent_);
157         }
158         TELEPHONY_LOGI("Initialize entry %{public}s", state->name_.c_str());
159         state->StateBegin();
160         curState_ = state;
161     }
162 
SendDeferredEvent()163     void SendDeferredEvent()
164     {
165         std::lock_guard<std::mutex> guard(mtx_);
166         if (deferEvents_.empty()) {
167             return;
168         }
169         for (size_t i = 0; i < deferEvents_.size(); ++i) {
170             AppExecFwk::InnerEvent::Pointer event = std::move(deferEvents_[i]);
171             SendImmediateEvent(event);
172         }
173         deferEvents_.clear();
174     }
175 
176 private:
177     sptr<State> originalState_;
178     sptr<State> destState_;
179     sptr<State> curState_;
180     std::vector<AppExecFwk::InnerEvent::Pointer> deferEvents_;
181     std::mutex mtx_;
182     bool isQuit_ = false;
183 };
184 
185 class StateMachine {
186 public:
StateMachine(const std::shared_ptr<AppExecFwk::EventRunner> & runner)187     explicit StateMachine(const std::shared_ptr<AppExecFwk::EventRunner> &runner)
188     {
189         stateMachineEventHandler_ = std::make_shared<StateMachineEventHandler>(runner);
190         if (stateMachineEventHandler_ == nullptr) {
191             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
192             return;
193         }
194     }
195 
~StateMachine()196     virtual ~StateMachine() {}
197 
Quit()198     void Quit()
199     {
200         AppExecFwk::InnerEvent::Pointer event =
201             AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STATE_MACHINE_QUIT);
202         if (stateMachineEventHandler_ == nullptr) {
203             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
204             return;
205         }
206         stateMachineEventHandler_->SendImmediateEvent(event);
207     }
208 
Start()209     void Start()
210     {
211         if (stateMachineEventHandler_ == nullptr) {
212             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
213             return;
214         }
215         AppExecFwk::InnerEvent::Pointer event =
216             AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STATE_MACHINE_INIT);
217         stateMachineEventHandler_->SendImmediateEvent(event);
218     }
219 
SetOriginalState(sptr<State> & originalState)220     void SetOriginalState(sptr<State> &originalState)
221     {
222         if (originalState == nullptr) {
223             TELEPHONY_LOGE("originalState is null");
224             return;
225         }
226         if (stateMachineEventHandler_ == nullptr) {
227             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
228             return;
229         }
230         stateMachineEventHandler_->SetOriginalState(originalState);
231     }
232 
TransitionTo(sptr<State> & destState)233     void TransitionTo(sptr<State> &destState)
234     {
235         if (destState == nullptr) {
236             TELEPHONY_LOGE("destState is null");
237             return;
238         }
239         if (stateMachineEventHandler_ == nullptr) {
240             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
241             return;
242         }
243         stateMachineEventHandler_->TransitionTo(destState);
244     }
245 
DeferEvent(const AppExecFwk::InnerEvent::Pointer && event)246     void DeferEvent(const AppExecFwk::InnerEvent::Pointer &&event)
247     {
248         if (stateMachineEventHandler_ == nullptr) {
249             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
250             return;
251         }
252         stateMachineEventHandler_->DeferEvent(std::move(const_cast<AppExecFwk::InnerEvent::Pointer &>(event)));
253     }
254 
SendEvent(AppExecFwk::InnerEvent::Pointer & event)255     void SendEvent(AppExecFwk::InnerEvent::Pointer &event)
256     {
257         if (stateMachineEventHandler_ == nullptr) {
258             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
259             return;
260         }
261         TELEPHONY_LOGI("State machine send event id %{public}u ", event->GetInnerEventId());
262         stateMachineEventHandler_->SendEvent(event);
263     }
264 
265 protected:
266     std::shared_ptr<StateMachineEventHandler> stateMachineEventHandler_;
267 };
268 } // namespace Telephony
269 } // namespace OHOS
270 #endif // STATE_MACHINE_H
271