1 /*
2 * Copyright (c) 2022 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 #include "finite_state_machine_impl.h"
16
17 #include <set>
18
19 #include "iam_logger.h"
20
21 #define LOG_TAG "USER_AUTH_SA"
22 namespace OHOS {
23 namespace UserIam {
24 namespace UserAuth {
25 using namespace OHOS;
FiniteStateMachineImpl(std::string name,uint32_t initialState,TransitionMap & transitionMap,EnterMap & enterMap,LeaveMap & leaveMap)26 FiniteStateMachineImpl::FiniteStateMachineImpl(std::string name, uint32_t initialState, TransitionMap &transitionMap,
27 EnterMap &enterMap, LeaveMap &leaveMap)
28 : name_(std::move(name)),
29 currentState_(initialState),
30 threadHandler_(ThreadHandler::GetSingleThreadInstance()),
31 transitionMap_(std::move(transitionMap)),
32 enterMap_(std::move(enterMap)),
33 leaveMap_(std::move(leaveMap))
34 {
35 IAM_LOGD("fsm %{public}s created for %{public}zu transitions", name_.c_str(), transitionMap_.size());
36 }
37
~FiniteStateMachineImpl()38 FiniteStateMachineImpl::~FiniteStateMachineImpl()
39 {
40 pendingEvents_.Clear();
41 IAM_LOGD("fsm %{public}s destroyed for %{public}zu transitions", name_.c_str(), transitionMap_.size());
42 }
43
Schedule(uint32_t event)44 void FiniteStateMachineImpl::Schedule(uint32_t event)
45 {
46 if (threadHandler_ == nullptr) {
47 IAM_LOGE("machine %{public}s 's threadHandler not set", GetMachineName().c_str());
48 return;
49 }
50 pendingEvents_.Push(event);
51 IAM_LOGI("fsm %{public}s new schedule event input:%{public}u", name_.c_str(), event);
52 threadHandler_->PostTask([self = weak_from_this(), this]() {
53 if (auto machine = self.lock(); machine != nullptr) {
54 Inner inner(machine);
55 ScheduleInner(inner);
56 }
57 });
58 }
59
ScheduleInner(FiniteStateMachine & machine)60 void FiniteStateMachineImpl::ScheduleInner(FiniteStateMachine &machine)
61 {
62 std::lock_guard<std::mutex> lock(mutex_);
63 for (uint32_t runTimes = 0; runTimes < FiniteStateMachineImpl::MAX_SCHEDULE_TIMES; runTimes++) {
64 uint32_t event = 0;
65 bool result = pendingEvents_.Pop(event);
66 if (!result) {
67 IAM_LOGI("fsm %{public}s pop event fail", name_.c_str());
68 break;
69 }
70
71 uint32_t oldState = currentState_;
72 auto iter = transitionMap_.find(GetTransitionIndex(currentState_, event));
73 if (iter != transitionMap_.end()) {
74 auto invoker = iter->second.second;
75 if (invoker) {
76 invoker(machine, event);
77 }
78 currentState_ = iter->second.first;
79 }
80
81 DealWithStateLeaveAndEnter(machine, oldState, currentState_);
82
83 IAM_LOGI("fsm %{public}s schedule [state:%{public}u] + [event:%{public}u] -> [nextState:%{public}u]",
84 name_.c_str(), oldState, event, currentState_);
85 if (runTimes >= FiniteStateMachineImpl::MAX_SCHEDULE_TIMES) {
86 IAM_LOGE("fsm %{public}s schedule too many times", name_.c_str());
87 break;
88 }
89 }
90 }
91
DealWithStateLeaveAndEnter(FiniteStateMachine & machine,uint32_t oldState,uint32_t newState)92 void FiniteStateMachineImpl::DealWithStateLeaveAndEnter(FiniteStateMachine &machine, uint32_t oldState,
93 uint32_t newState)
94 {
95 if (oldState == newState) {
96 return;
97 }
98 if (auto iter = leaveMap_.find(oldState); iter != leaveMap_.end()) {
99 if (auto invoker = iter->second; invoker) {
100 invoker(machine, oldState);
101 }
102 }
103
104 if (auto iter = enterMap_.find(currentState_); iter != enterMap_.end()) {
105 if (auto invoker = iter->second; invoker) {
106 invoker(machine, currentState_);
107 }
108 }
109 }
110
GetCurrentState() const111 uint32_t FiniteStateMachineImpl::GetCurrentState() const
112 {
113 return currentState_;
114 }
115
EnsureCurrentState()116 uint32_t FiniteStateMachineImpl::EnsureCurrentState()
117 {
118 if (threadHandler_) {
119 threadHandler_->EnsureTask([]() {});
120 }
121
122 return currentState_;
123 }
124
GetMachineName() const125 const std::string &FiniteStateMachineImpl::GetMachineName() const
126 {
127 return name_;
128 }
129
SetThreadHandler(const std::shared_ptr<ThreadHandler> & threadHandler)130 void FiniteStateMachineImpl::SetThreadHandler(const std::shared_ptr<ThreadHandler> &threadHandler)
131 {
132 threadHandler_ = threadHandler;
133 }
134
Inner(std::shared_ptr<FiniteStateMachineImpl> & machine)135 FiniteStateMachineImpl::Inner::Inner(std::shared_ptr<FiniteStateMachineImpl> &machine) : machine_(machine)
136 {
137 }
138
Schedule(uint32_t event)139 void FiniteStateMachineImpl::Inner::Schedule(uint32_t event)
140 {
141 machine_->pendingEvents_.Push(event);
142 }
143
GetCurrentState() const144 uint32_t FiniteStateMachineImpl::Inner::GetCurrentState() const
145 {
146 return machine_->GetCurrentState();
147 }
148
EnsureCurrentState()149 uint32_t FiniteStateMachineImpl::Inner::EnsureCurrentState()
150 {
151 return machine_->GetCurrentState();
152 }
153
GetMachineName() const154 const std::string &FiniteStateMachineImpl::Inner::GetMachineName() const
155 {
156 return machine_->GetMachineName();
157 }
158
SetThreadHandler(const std::shared_ptr<ThreadHandler> & threadHandler)159 void FiniteStateMachineImpl::Inner::SetThreadHandler(const std::shared_ptr<ThreadHandler> &threadHandler)
160 {
161 IAM_LOGE("can not set thread handler inner");
162 }
163 } // namespace UserAuth
164 } // namespace UserIam
165 } // namespace OHOS
166