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 "cellular_data_event_code.h"
25 #include "inner_event.h"
26 #include "tel_event_handler.h"
27 #include "telephony_log_wrapper.h"
28 
29 namespace OHOS {
30 namespace Telephony {
31 class State : public RefBase {
32 #define PROCESSED true
33 #define NOT_PROCESSED false
34 public:
State(std::string && name)35     explicit State(std::string &&name) : name_(std::move(name)) {}
36     virtual ~State() = default;
37     virtual void StateBegin() = 0;
38     virtual void StateEnd() = 0;
39     virtual bool StateProcess(const AppExecFwk::InnerEvent::Pointer &event) = 0;
40 
SetParentState(sptr<State> & parent)41     void SetParentState(sptr<State> &parent)
42     {
43         parent_ = parent;
44     }
45 
GetStateMachineName()46     std::string GetStateMachineName() const
47     {
48         return name_;
49     }
50 
51 protected:
52     friend class StateMachineEventHandler;
53     std::string name_;
54     sptr<State> parent_;
55     bool isActive_ = false;
56 };
57 
58 class StateMachineEventHandler : public TelEventHandler {
59 public:
StateMachineEventHandler(const std::string & name)60     explicit StateMachineEventHandler(const std::string &name) : TelEventHandler(name) {}
61     ~StateMachineEventHandler() = default;
62 
SetOriginalState(sptr<State> & originalState)63     virtual void SetOriginalState(sptr<State> &originalState)
64     {
65         originalState_ = originalState;
66     }
67 
TransitionTo(sptr<State> & destState)68     virtual void TransitionTo(sptr<State> &destState)
69     {
70         TELEPHONY_LOGI("State machine transition to %{public}s", destState->name_.c_str());
71         destState_ = destState;
72     }
73 
Quit()74     virtual void Quit()
75     {
76         sptr<State> tmpState = curState_;
77         while (tmpState != nullptr && tmpState->isActive_) {
78             tmpState->StateEnd();
79             tmpState = tmpState->parent_;
80             isQuit_ = true;
81         }
82     }
83 
84     // Only two-layer StateMachines are supported
ProcessTransitions(const AppExecFwk::InnerEvent::Pointer & event)85     virtual void ProcessTransitions(const AppExecFwk::InnerEvent::Pointer &event)
86     {
87         if (curState_ != destState_) {
88             TELEPHONY_LOGD("Begin process transitions");
89             if (curState_ != nullptr) {
90                 sptr<State> tmpState = curState_->parent_;
91                 while (tmpState != nullptr) {
92                     tmpState->StateEnd();
93                     tmpState = tmpState->parent_;
94                 }
95                 curState_->StateEnd();
96             }
97             if (destState_ != nullptr) {
98                 sptr<State> tmpState = destState_->parent_;
99                 while (tmpState != nullptr) {
100                     tmpState->StateBegin();
101                     tmpState = tmpState->parent_;
102                 }
103                 destState_->StateBegin();
104             }
105             curState_ = destState_;
106             SendDeferredEvent();
107         }
108     }
109 
DeferEvent(AppExecFwk::InnerEvent::Pointer && event)110     void DeferEvent(AppExecFwk::InnerEvent::Pointer &&event)
111     {
112         std::lock_guard<std::mutex> guard(mtx_);
113         deferEvents_.push_back(std::move(event));
114     }
115 
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)116     virtual void ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
117     {
118         if (event == nullptr || isQuit_) {
119             TELEPHONY_LOGE("The event parameter is incorrect");
120             return;
121         }
122         if (event->GetInnerEventId() == CellularDataEventCode::MSG_STATE_MACHINE_QUIT) {
123             TELEPHONY_LOGI("State machine exit");
124             Quit();
125             return;
126         }
127         if (event->GetInnerEventId() == CellularDataEventCode::MSG_STATE_MACHINE_INIT) {
128             destState_ = originalState_;
129             InitCmdEnter(originalState_);
130         }
131         ProcessMsg(event);
132         ProcessTransitions(event);
133     }
134 
ProcessMsg(const AppExecFwk::InnerEvent::Pointer & event)135     virtual void ProcessMsg(const AppExecFwk::InnerEvent::Pointer &event)
136     {
137         sptr<State> tmpState = curState_;
138         TELEPHONY_LOGD("The event id: %{public}u", event->GetInnerEventId());
139         while (tmpState != nullptr && !tmpState->StateProcess(event)) {
140             tmpState = tmpState->parent_;
141         }
142     }
143 
144 private:
InitCmdEnter(const sptr<State> & state)145     void InitCmdEnter(const sptr<State> &state)
146     {
147         if (state == nullptr) {
148             TELEPHONY_LOGE("registerState_ is null");
149             return;
150         }
151         if (state->parent_ != nullptr) {
152             InitCmdEnter(state->parent_);
153         }
154         TELEPHONY_LOGI("Initialize entry %{public}s", state->name_.c_str());
155         state->StateBegin();
156         curState_ = state;
157     }
158 
SendDeferredEvent()159     void SendDeferredEvent()
160     {
161         std::lock_guard<std::mutex> guard(mtx_);
162         if (deferEvents_.empty()) {
163             return;
164         }
165         for (size_t i = 0; i < deferEvents_.size(); ++i) {
166             AppExecFwk::InnerEvent::Pointer event = std::move(deferEvents_[i]);
167             SendImmediateEvent(event);
168         }
169         deferEvents_.clear();
170     }
171 
172 private:
173     sptr<State> originalState_;
174     sptr<State> destState_;
175     sptr<State> curState_;
176     std::vector<AppExecFwk::InnerEvent::Pointer> deferEvents_;
177     std::mutex mtx_;
178     bool isQuit_ = false;
179 };
180 
181 class StateMachine {
182 public:
StateMachine(const std::string & name)183     explicit StateMachine(const std::string &name)
184     {
185         stateMachineEventHandler_ = std::make_shared<StateMachineEventHandler>(name);
186         if (stateMachineEventHandler_ == nullptr) {
187             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
188             return;
189         }
190     }
191 
~StateMachine()192     virtual ~StateMachine() {}
193 
Quit()194     void Quit()
195     {
196         AppExecFwk::InnerEvent::Pointer event =
197             AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STATE_MACHINE_QUIT);
198         if (stateMachineEventHandler_ == nullptr) {
199             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
200             return;
201         }
202         stateMachineEventHandler_->SendImmediateEvent(event);
203     }
204 
Start()205     void Start()
206     {
207         if (stateMachineEventHandler_ == nullptr) {
208             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
209             return;
210         }
211         AppExecFwk::InnerEvent::Pointer event =
212             AppExecFwk::InnerEvent::Get(CellularDataEventCode::MSG_STATE_MACHINE_INIT);
213         stateMachineEventHandler_->SendImmediateEvent(event);
214     }
215 
SetOriginalState(sptr<State> & originalState)216     void SetOriginalState(sptr<State> &originalState)
217     {
218         if (originalState == nullptr) {
219             TELEPHONY_LOGE("originalState is null");
220             return;
221         }
222         if (stateMachineEventHandler_ == nullptr) {
223             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
224             return;
225         }
226         stateMachineEventHandler_->SetOriginalState(originalState);
227     }
228 
TransitionTo(sptr<State> & destState)229     void TransitionTo(sptr<State> &destState)
230     {
231         if (destState == nullptr) {
232             TELEPHONY_LOGE("destState is null");
233             return;
234         }
235         if (stateMachineEventHandler_ == nullptr) {
236             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
237             return;
238         }
239         stateMachineEventHandler_->TransitionTo(destState);
240     }
241 
DeferEvent(const AppExecFwk::InnerEvent::Pointer && event)242     void DeferEvent(const AppExecFwk::InnerEvent::Pointer &&event)
243     {
244         if (stateMachineEventHandler_ == nullptr) {
245             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
246             return;
247         }
248         stateMachineEventHandler_->DeferEvent(std::move(const_cast<AppExecFwk::InnerEvent::Pointer &>(event)));
249     }
250 
SendEvent(AppExecFwk::InnerEvent::Pointer & event)251     void SendEvent(AppExecFwk::InnerEvent::Pointer &event)
252     {
253         if (stateMachineEventHandler_ == nullptr) {
254             TELEPHONY_LOGE("stateMachineEventHandler_ is null");
255             return;
256         }
257         if (event == nullptr) {
258             TELEPHONY_LOGE("event is null");
259             return;
260         }
261         TELEPHONY_LOGD("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