1 /*
2  * Copyright (c) 2023 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 "FACE_AUTH_SA"
22 namespace OHOS {
23 namespace UserIam {
24 namespace FaceAuth {
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_LOGI("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_LOGI("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     uint32_t runTimes = 0;
64     while (true) {
65         uint32_t event = 0;
66         bool result = pendingEvents_.Pop(event);
67         if (!result) {
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 
86         ++runTimes;
87         if (runTimes >= FiniteStateMachineImpl::MAX_SCHEDULE_TIMES) {
88             IAM_LOGE("fsm %{public}s schedule too many times", name_.c_str());
89             break;
90         }
91     }
92 }
93 
DealWithStateLeaveAndEnter(FiniteStateMachine & machine,uint32_t oldState,uint32_t newState)94 void FiniteStateMachineImpl::DealWithStateLeaveAndEnter(FiniteStateMachine &machine, uint32_t oldState,
95     uint32_t newState)
96 {
97     if (oldState == newState) {
98         return;
99     }
100     if (auto iter = leaveMap_.find(oldState); iter != leaveMap_.end()) {
101         if (auto invoker = iter->second; invoker) {
102             invoker(machine, oldState);
103         }
104     }
105 
106     if (auto iter = enterMap_.find(currentState_); iter != enterMap_.end()) {
107         if (auto invoker = iter->second; invoker) {
108             invoker(machine, currentState_);
109         }
110     }
111 }
112 
GetCurrentState() const113 uint32_t FiniteStateMachineImpl::GetCurrentState() const
114 {
115     return currentState_;
116 }
117 
EnsureCurrentState()118 uint32_t FiniteStateMachineImpl::EnsureCurrentState()
119 {
120     if (threadHandler_) {
121         threadHandler_->EnsureTask(nullptr);
122     }
123 
124     return currentState_;
125 }
126 
GetMachineName() const127 const std::string &FiniteStateMachineImpl::GetMachineName() const
128 {
129     return name_;
130 }
131 
SetThreadHandler(const std::shared_ptr<ThreadHandler> & threadHandler)132 void FiniteStateMachineImpl::SetThreadHandler(const std::shared_ptr<ThreadHandler> &threadHandler)
133 {
134     threadHandler_ = threadHandler;
135 }
136 
Inner(std::shared_ptr<FiniteStateMachineImpl> & machine)137 FiniteStateMachineImpl::Inner::Inner(std::shared_ptr<FiniteStateMachineImpl> &machine) : machine_(machine)
138 {
139 }
140 
Schedule(uint32_t event)141 void FiniteStateMachineImpl::Inner::Schedule(uint32_t event)
142 {
143     machine_->pendingEvents_.Push(event);
144 }
145 
GetCurrentState() const146 uint32_t FiniteStateMachineImpl::Inner::GetCurrentState() const
147 {
148     return machine_->GetCurrentState();
149 }
150 
EnsureCurrentState()151 uint32_t FiniteStateMachineImpl::Inner::EnsureCurrentState()
152 {
153     return machine_->GetCurrentState();
154 }
155 
GetMachineName() const156 const std::string &FiniteStateMachineImpl::Inner::GetMachineName() const
157 {
158     return machine_->GetMachineName();
159 }
160 
SetThreadHandler(const std::shared_ptr<ThreadHandler> & threadHandler)161 void FiniteStateMachineImpl::Inner::SetThreadHandler(const std::shared_ptr<ThreadHandler> &threadHandler)
162 {
163     IAM_LOGE("can not set thread handler inner");
164 }
165 } // namespace FaceAuth
166 } // namespace UserIam
167 } // namespace OHOS
168