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 "schedule_node_impl.h"
16
17 #include <mutex>
18 #include <sstream>
19
20 #include "nocopyable.h"
21
22 #include "iam_logger.h"
23 #include "iam_ptr.h"
24 #include "iam_para2str.h"
25 #include "iam_common_defines.h"
26 #include "relative_timer.h"
27
28 #define LOG_LABEL UserIam::Common::LABEL_USER_AUTH_SA
29
30 namespace OHOS {
31 namespace UserIam {
32 namespace UserAuth {
ScheduleNodeImpl(ScheduleInfo & info)33 ScheduleNodeImpl::ScheduleNodeImpl(ScheduleInfo &info) : info_(std::move(info))
34 {
35 machine_ = MakeFiniteStateMachine();
36 if (machine_ && info_.threadHandler == nullptr) {
37 info_.threadHandler = ThreadHandler::GetSingleThreadInstance();
38 machine_->SetThreadHandler(info_.threadHandler);
39 }
40 if (info_.parameters == nullptr) {
41 info_.parameters = Common::MakeShared<Attributes>();
42 }
43
44 if (info_.parameters == nullptr) {
45 return;
46 }
47
48 info_.parameters->SetInt32Value(Attributes::ATTR_SCHEDULE_MODE, info_.scheduleMode);
49
50 if (info_.tokenId.has_value()) {
51 info_.parameters->SetUint32Value(Attributes::ATTR_ACCESS_TOKEN_ID, info_.tokenId.value());
52 }
53
54 if (info_.pinSubType != 0) {
55 info_.parameters->SetInt32Value(Attributes::ATTR_PIN_SUB_TYPE, info_.pinSubType);
56 }
57
58 info_.parameters->SetBoolValue(Attributes::ATTR_END_AFTER_FIRST_FAIL, info_.endAfterFirstFail);
59 info_.parameters->SetUint8ArrayValue(Attributes::ATTR_EXTRA_INFO, info_.extraInfo);
60
61 if (info_.templateIdList.empty()) {
62 return;
63 }
64
65 info_.parameters->SetUint64ArrayValue(Attributes::ATTR_TEMPLATE_ID_LIST, info_.templateIdList);
66 if (info_.templateIdList.size() == 1) {
67 info_.parameters->SetUint64Value(Attributes::ATTR_TEMPLATE_ID, *info_.templateIdList.begin());
68 }
69 }
70
GetScheduleId() const71 uint64_t ScheduleNodeImpl::GetScheduleId() const
72 {
73 return info_.scheduleId;
74 }
75
GetContextId() const76 uint64_t ScheduleNodeImpl::GetContextId() const
77 {
78 return info_.contextId;
79 }
80
GetAuthType() const81 AuthType ScheduleNodeImpl::GetAuthType() const
82 {
83 return info_.authType;
84 }
85
GetExecutorMatcher() const86 uint64_t ScheduleNodeImpl::GetExecutorMatcher() const
87 {
88 return info_.executorMatcher;
89 }
90
GetScheduleMode() const91 ScheduleMode ScheduleNodeImpl::GetScheduleMode() const
92 {
93 return info_.scheduleMode;
94 }
95
GetCollectorExecutor() const96 std::weak_ptr<ResourceNode> ScheduleNodeImpl::GetCollectorExecutor() const
97 {
98 return info_.collector;
99 }
100
GetVerifyExecutor() const101 std::weak_ptr<ResourceNode> ScheduleNodeImpl::GetVerifyExecutor() const
102 {
103 return info_.verifier;
104 }
105
GetTemplateIdList() const106 std::optional<std::vector<uint64_t>> ScheduleNodeImpl::GetTemplateIdList() const
107 {
108 if (info_.templateIdList.empty()) {
109 return std::nullopt;
110 }
111 return info_.templateIdList;
112 }
113
GetCurrentScheduleState() const114 ScheduleNode::State ScheduleNodeImpl::GetCurrentScheduleState() const
115 {
116 if (machine_ == nullptr) {
117 return S_INIT;
118 }
119 return static_cast<State>(machine_->GetCurrentState());
120 }
121
StartSchedule()122 bool ScheduleNodeImpl::StartSchedule()
123 {
124 iamHitraceHelper_ = Common::MakeShared<IamHitraceHelper>(GetDescription());
125 {
126 std::lock_guard<std::mutex> lock(mutex_);
127 if (!TryKickMachine(E_START_AUTH)) {
128 return false;
129 }
130 }
131 StartTimer();
132 return true;
133 }
134
StopSchedule()135 bool ScheduleNodeImpl::StopSchedule()
136 {
137 std::lock_guard<std::mutex> lock(mutex_);
138
139 SetFwkResultCode(CANCELED);
140 return TryKickMachine(E_STOP_AUTH);
141 }
142
ContinueSchedule(ExecutorRole srcRole,ExecutorRole dstRole,uint64_t transNum,const std::vector<uint8_t> & msg)143 bool ScheduleNodeImpl::ContinueSchedule(ExecutorRole srcRole, ExecutorRole dstRole, uint64_t transNum,
144 const std::vector<uint8_t> &msg)
145 {
146 if (dstRole != SCHEDULER) {
147 IAM_LOGE("not supported yet");
148 return false;
149 }
150
151 if (info_.callback) {
152 info_.callback->OnScheduleProcessed(srcRole, GetAuthType(), msg);
153 }
154
155 return true;
156 }
157
ContinueSchedule(ResultCode resultCode,const std::shared_ptr<Attributes> & finalResult)158 bool ScheduleNodeImpl::ContinueSchedule(ResultCode resultCode, const std::shared_ptr<Attributes> &finalResult)
159 {
160 std::lock_guard<std::mutex> lock(mutex_);
161 SetExecutorResultCode(resultCode);
162 SetScheduleResult(finalResult);
163 return TryKickMachine(E_SCHEDULE_RESULT_RECEIVED);
164 }
165
MakeFiniteStateMachine()166 std::shared_ptr<FiniteStateMachine> ScheduleNodeImpl::MakeFiniteStateMachine()
167 {
168 auto builder = FiniteStateMachine::Builder::New(GetDescription(), S_INIT);
169 if (builder == nullptr) {
170 return nullptr;
171 }
172 // S_INIT
173 builder->MakeTransition(S_INIT, E_START_AUTH, S_VERIFY_STARING,
174 [this](FiniteStateMachine &machine, uint32_t event) { ProcessBeginVerifier(machine, event); });
175
176 // S_VERIFY_STARING
177 builder->MakeTransition(S_VERIFY_STARING, E_VERIFY_STARTED_SUCCESS, S_COLLECT_STARING,
178 [this](FiniteStateMachine &machine, uint32_t event) { ProcessBeginCollector(machine, event); });
179 builder->MakeTransition(S_VERIFY_STARING, E_VERIFY_STARTED_FAILED, S_END,
180 [this](FiniteStateMachine &machine, uint32_t event) { ProcessVerifierBeginFailed(machine, event); });
181 builder->MakeTransition(S_VERIFY_STARING, E_SCHEDULE_RESULT_RECEIVED, S_END);
182 builder->MakeTransition(S_VERIFY_STARING, E_STOP_AUTH, S_VERIFY_STOPPING,
183 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
184 builder->MakeTransition(S_VERIFY_STARING, E_TIME_OUT, S_VERIFY_STOPPING,
185 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
186
187 // S_COLLECT_STARING
188 builder->MakeTransition(S_COLLECT_STARING, E_COLLECT_STARTED_SUCCESS, S_AUTH_PROCESSING);
189 builder->MakeTransition(S_COLLECT_STARING, E_SCHEDULE_RESULT_RECEIVED, S_END);
190 builder->MakeTransition(S_COLLECT_STARING, E_STOP_AUTH, S_COLLECT_STOPPING,
191 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
192
193 // S_AUTH_PROCESSING
194 builder->MakeTransition(S_AUTH_PROCESSING, E_SCHEDULE_RESULT_RECEIVED, S_END);
195 builder->MakeTransition(S_AUTH_PROCESSING, E_STOP_AUTH, S_COLLECT_STOPPING,
196 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
197 builder->MakeTransition(S_AUTH_PROCESSING, E_TIME_OUT, S_COLLECT_STOPPING,
198 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
199
200 // S_COLLECT_STOPPING
201 builder->MakeTransition(S_COLLECT_STOPPING, E_SCHEDULE_RESULT_RECEIVED, S_END);
202 builder->MakeTransition(S_COLLECT_STOPPING, E_COLLECT_STOPPED_SUCCESS, S_VERIFY_STOPPING,
203 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
204 builder->MakeTransition(S_COLLECT_STOPPING, E_COLLECT_STOPPED_FAILED, S_VERIFY_STOPPING,
205 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
206 builder->MakeTransition(S_COLLECT_STOPPING, E_TIME_OUT, S_VERIFY_STOPPING,
207 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
208
209 // S_VERIFY_STOPPING
210 builder->MakeTransition(S_VERIFY_STOPPING, E_SCHEDULE_RESULT_RECEIVED, S_END);
211 builder->MakeTransition(S_VERIFY_STOPPING, E_VERIFY_STOPPED_SUCCESS, S_END);
212 builder->MakeTransition(S_VERIFY_STOPPING, E_VERIFY_STOPPED_FAILED, S_END);
213 builder->MakeTransition(S_VERIFY_STOPPING, E_TIME_OUT, S_END);
214
215 // ENTERS
216 builder->MakeOnStateEnter(S_AUTH_PROCESSING,
217 [this](FiniteStateMachine &machine, uint32_t event) { OnScheduleProcessing(machine, event); });
218 builder->MakeOnStateEnter(S_END,
219 [this](FiniteStateMachine &machine, uint32_t event) { OnScheduleFinished(machine, event); });
220 return builder->Build();
221 }
222
GetDescription() const223 std::string ScheduleNodeImpl::GetDescription() const
224 {
225 std::ostringstream ss;
226
227 auto verifier = info_.verifier.lock();
228 ss << "schedule type:" << (verifier ? Common::AuthTypeToStr(verifier->GetAuthType()) : "nullptr") <<
229 " id:******" << std::hex << static_cast<uint16_t>(GetScheduleId());
230 return ss.str();
231 }
232
TryKickMachine(Event event)233 bool ScheduleNodeImpl::TryKickMachine(Event event)
234 {
235 if (machine_ == nullptr) {
236 return false;
237 }
238 machine_->Schedule(event);
239 return true;
240 }
241
SetFwkResultCode(int32_t resultCode)242 void ScheduleNodeImpl::SetFwkResultCode(int32_t resultCode)
243 {
244 fwkResultCode_ = resultCode;
245 }
246
SetExecutorResultCode(int32_t resultCode)247 void ScheduleNodeImpl::SetExecutorResultCode(int32_t resultCode)
248 {
249 executorResultCode_ = resultCode;
250 }
251
SetScheduleResult(const std::shared_ptr<Attributes> & scheduleResult)252 void ScheduleNodeImpl::SetScheduleResult(const std::shared_ptr<Attributes> &scheduleResult)
253 {
254 scheduleResult_ = scheduleResult;
255 }
256
StartTimer()257 void ScheduleNodeImpl::StartTimer()
258 {
259 std::lock_guard<std::mutex> lock(mutex_);
260 if (info_.expiredTime == 0 || timerId_ != 0) {
261 return;
262 }
263
264 timerId_ = RelativeTimer::GetInstance().Register(
265 [self = weak_from_this(), this] {
266 if (self.lock()) {
267 std::lock_guard<std::mutex> lock(mutex_);
268 SetFwkResultCode(TIMEOUT);
269 TryKickMachine(E_TIME_OUT);
270 }
271 },
272 info_.expiredTime);
273 }
274
StopTimer()275 void ScheduleNodeImpl::StopTimer()
276 {
277 std::lock_guard<std::mutex> lock(mutex_);
278 if (timerId_ == 0) {
279 return;
280 }
281 RelativeTimer::GetInstance().Unregister(timerId_);
282 timerId_ = 0;
283 }
284
ProcessBeginVerifier(FiniteStateMachine & machine,uint32_t event)285 void ScheduleNodeImpl::ProcessBeginVerifier(FiniteStateMachine &machine, uint32_t event)
286 {
287 auto collector = info_.collector.lock();
288 auto verifier = info_.verifier.lock();
289 if (collector == nullptr || verifier == nullptr) {
290 SetFwkResultCode(GENERAL_ERROR);
291 machine.Schedule(E_VERIFY_STARTED_FAILED);
292 IAM_LOGE("invalid resource");
293 return;
294 }
295 auto peerPk = collector->GetExecutorPublicKey();
296
297 auto result = verifier->BeginExecute(info_.scheduleId, peerPk, *info_.parameters);
298 if (result != SUCCESS) {
299 IAM_LOGE("start verify failed, result = %{public}d", result);
300 SetExecutorResultCode(result);
301 machine.Schedule(E_VERIFY_STARTED_FAILED);
302 return;
303 }
304 IAM_LOGI("start verify success");
305 machine.Schedule(E_VERIFY_STARTED_SUCCESS);
306 }
307
ProcessBeginCollector(FiniteStateMachine & machine,uint32_t event)308 void ScheduleNodeImpl::ProcessBeginCollector(FiniteStateMachine &machine, uint32_t event)
309 {
310 auto collector = info_.collector.lock();
311 auto verifier = info_.verifier.lock();
312 if (collector == nullptr || verifier == nullptr) {
313 SetFwkResultCode(GENERAL_ERROR);
314 machine.Schedule(E_COLLECT_STARTED_FAILED);
315 IAM_LOGE("invalid resource");
316 return;
317 }
318 if (collector == verifier) {
319 IAM_LOGI("all in one schedule, just wait the result");
320 machine.Schedule(E_COLLECT_STARTED_SUCCESS);
321 return;
322 }
323 IAM_LOGE("distributed auth not supported yet");
324 }
325
ProcessVerifierBeginFailed(FiniteStateMachine & machine,uint32_t event)326 void ScheduleNodeImpl::ProcessVerifierBeginFailed(FiniteStateMachine &machine, uint32_t event)
327 {
328 // just do nothing
329 }
330
ProcessCollectorBeginFailed(FiniteStateMachine & machine,uint32_t event)331 void ScheduleNodeImpl::ProcessCollectorBeginFailed(FiniteStateMachine &machine, uint32_t event)
332 {
333 // just do nothing
334 }
335
ProcessScheduleResultReceived(FiniteStateMachine & machine,uint32_t event) const336 void ScheduleNodeImpl::ProcessScheduleResultReceived(FiniteStateMachine &machine, uint32_t event) const
337 {
338 // just do nothing
339 }
340
ProcessEndCollector(FiniteStateMachine & machine,uint32_t event)341 void ScheduleNodeImpl::ProcessEndCollector(FiniteStateMachine &machine, uint32_t event)
342 {
343 auto collector = info_.collector.lock();
344 auto verifier = info_.verifier.lock();
345 if (collector == nullptr || verifier == nullptr) {
346 SetFwkResultCode(GENERAL_ERROR);
347 machine.Schedule(E_COLLECT_STOPPED_FAILED);
348 return;
349 }
350 if (collector == verifier) {
351 IAM_LOGE("all in one schedule, just do noting");
352 machine.Schedule(E_COLLECT_STOPPED_SUCCESS);
353 return;
354 }
355 IAM_LOGE("distributed auth not supported yet");
356 }
357
ProcessEndVerifier(FiniteStateMachine & machine,uint32_t event)358 void ScheduleNodeImpl::ProcessEndVerifier(FiniteStateMachine &machine, uint32_t event)
359 {
360 auto verifier = info_.verifier.lock();
361 if (verifier == nullptr) {
362 SetFwkResultCode(GENERAL_ERROR);
363 machine.Schedule(E_VERIFY_STOPPED_FAILED);
364 return;
365 }
366 Attributes attr;
367 auto result = verifier->EndExecute(info_.scheduleId, attr);
368 if (result != SUCCESS) {
369 IAM_LOGE("end verify failed, result = %{public}d", result);
370 SetExecutorResultCode(result);
371 machine.Schedule(E_VERIFY_STOPPED_FAILED);
372 return;
373 }
374 machine.Schedule(E_VERIFY_STOPPED_SUCCESS);
375 }
376
OnScheduleProcessing(FiniteStateMachine & machine,uint32_t event) const377 void ScheduleNodeImpl::OnScheduleProcessing(FiniteStateMachine &machine, uint32_t event) const
378 {
379 if (!info_.callback) {
380 return;
381 }
382 info_.callback->OnScheduleStarted();
383 }
384
OnScheduleFinished(FiniteStateMachine & machine,uint32_t event)385 void ScheduleNodeImpl::OnScheduleFinished(FiniteStateMachine &machine, uint32_t event)
386 {
387 StopTimer();
388 if (!info_.callback) {
389 return;
390 }
391
392 iamHitraceHelper_ = nullptr;
393
394 int32_t result = fwkResultCode_.value_or(executorResultCode_);
395 IAM_LOGI("schedule result = %{public}d", result);
396 info_.callback->OnScheduleStoped(result, scheduleResult_);
397 info_.callback = nullptr;
398 }
399 } // namespace UserAuth
400 } // namespace UserIam
401 } // namespace OHOS
402