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