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 "attributes.h"
23 #include "hdi_wrapper.h"
24 #include "iam_check.h"
25 #include "iam_logger.h"
26 #include "iam_ptr.h"
27 #include "iam_para2str.h"
28 #include "iam_common_defines.h"
29 #include "relative_timer.h"
30 #include "schedule_resource_node_listener.h"
31
32 #define LOG_TAG "USER_AUTH_SA"
33
34 namespace OHOS {
35 namespace UserIam {
36 namespace UserAuth {
ScheduleNodeImpl(ScheduleInfo & info)37 ScheduleNodeImpl::ScheduleNodeImpl(ScheduleInfo &info) : info_(std::move(info))
38 {
39 machine_ = MakeFiniteStateMachine();
40 if (machine_ && info_.threadHandler == nullptr) {
41 info_.threadHandler = ThreadHandler::GetSingleThreadInstance();
42 machine_->SetThreadHandler(info_.threadHandler);
43 }
44 }
45
~ScheduleNodeImpl()46 ScheduleNodeImpl::~ScheduleNodeImpl()
47 {
48 if (resourceNodePoolListener_ != nullptr) {
49 ResourceNodePool::Instance().DeregisterResourceNodePoolListener(resourceNodePoolListener_);
50 }
51 }
52
GetScheduleAttribute(bool isVerifier,Attributes & attribute) const53 void ScheduleNodeImpl::GetScheduleAttribute(bool isVerifier, Attributes &attribute) const
54 {
55 attribute.SetInt32Value(Attributes::ATTR_SCHEDULE_MODE, info_.scheduleMode);
56
57 if (info_.tokenId.has_value()) {
58 attribute.SetUint32Value(Attributes::ATTR_ACCESS_TOKEN_ID, info_.tokenId.value());
59 }
60
61 if (info_.pinSubType != 0) {
62 attribute.SetInt32Value(Attributes::ATTR_PIN_SUB_TYPE, info_.pinSubType);
63 }
64
65 attribute.SetUint32Value(Attributes::ATTR_COLLECTOR_TOKEN_ID, info_.collectorTokenId);
66 attribute.SetBoolValue(Attributes::ATTR_END_AFTER_FIRST_FAIL, info_.endAfterFirstFail);
67 IAM_LOGI("verifier message length = %{public}zu, collector message length = %{public}zu",
68 info_.verifierMessage.size(), info_.collectorMessage.size());
69
70 if (isVerifier) {
71 attribute.SetInt32Value(Attributes::ATTR_AUTH_INTENTION, info_.authIntent);
72 attribute.SetInt32Value(Attributes::ATTR_USER_ID, info_.userId);
73 attribute.SetUint8ArrayValue(Attributes::ATTR_EXTRA_INFO, info_.verifierMessage);
74 } else {
75 attribute.SetUint8ArrayValue(Attributes::ATTR_EXTRA_INFO, info_.collectorMessage);
76 }
77
78 if (!info_.templateIdList.empty()) {
79 attribute.SetUint64ArrayValue(Attributes::ATTR_TEMPLATE_ID_LIST, info_.templateIdList);
80 if (info_.templateIdList.size() == 1) {
81 attribute.SetUint64Value(Attributes::ATTR_TEMPLATE_ID, *info_.templateIdList.begin());
82 }
83 }
84 }
85
GetScheduleId() const86 uint64_t ScheduleNodeImpl::GetScheduleId() const
87 {
88 return info_.scheduleId;
89 }
90
GetContextId() const91 uint64_t ScheduleNodeImpl::GetContextId() const
92 {
93 return info_.contextId;
94 }
95
GetAuthType() const96 AuthType ScheduleNodeImpl::GetAuthType() const
97 {
98 return info_.authType;
99 }
100
GetExecutorMatcher() const101 uint64_t ScheduleNodeImpl::GetExecutorMatcher() const
102 {
103 return info_.executorMatcher;
104 }
105
GetScheduleMode() const106 ScheduleMode ScheduleNodeImpl::GetScheduleMode() const
107 {
108 return info_.scheduleMode;
109 }
110
GetCollectorExecutor() const111 std::weak_ptr<ResourceNode> ScheduleNodeImpl::GetCollectorExecutor() const
112 {
113 return info_.collector;
114 }
115
GetVerifyExecutor() const116 std::weak_ptr<ResourceNode> ScheduleNodeImpl::GetVerifyExecutor() const
117 {
118 return info_.verifier;
119 }
120
GetTemplateIdList() const121 std::optional<std::vector<uint64_t>> ScheduleNodeImpl::GetTemplateIdList() const
122 {
123 if (info_.templateIdList.empty()) {
124 return std::nullopt;
125 }
126 return info_.templateIdList;
127 }
128
GetCurrentScheduleState() const129 ScheduleNode::State ScheduleNodeImpl::GetCurrentScheduleState() const
130 {
131 if (machine_ == nullptr) {
132 return S_INIT;
133 }
134 return static_cast<State>(machine_->GetCurrentState());
135 }
136
GetScheduleCallback()137 std::shared_ptr<ScheduleNodeCallback> ScheduleNodeImpl::GetScheduleCallback()
138 {
139 std::lock_guard<std::mutex> lock(mutex_);
140 return info_.callback;
141 }
142
GetAuthIntent() const143 int32_t ScheduleNodeImpl::GetAuthIntent() const
144 {
145 return info_.authIntent;
146 }
147
ClearScheduleCallback()148 void ScheduleNodeImpl::ClearScheduleCallback()
149 {
150 std::lock_guard<std::mutex> lock(mutex_);
151 info_.callback = nullptr;
152 }
153
StartSchedule()154 bool ScheduleNodeImpl::StartSchedule()
155 {
156 iamHitraceHelper_ = Common::MakeShared<IamHitraceHelper>(GetDescription());
157 {
158 std::lock_guard<std::mutex> lock(mutex_);
159 resourceNodePoolListener_ = Common::MakeShared<ScheduleResourceNodeListener>(weak_from_this());
160 IF_FALSE_LOGE_AND_RETURN_VAL(resourceNodePoolListener_ != nullptr, false);
161 bool registerRet = ResourceNodePool::Instance().RegisterResourceNodePoolListener(resourceNodePoolListener_);
162 IF_FALSE_LOGE_AND_RETURN_VAL(registerRet, false);
163 if (!TryKickMachine(E_START_AUTH)) {
164 return false;
165 }
166 }
167 StartTimer();
168 return true;
169 }
170
StopSchedule()171 bool ScheduleNodeImpl::StopSchedule()
172 {
173 return StopSchedule(CANCELED);
174 }
175
StopSchedule(ResultCode errorCode)176 bool ScheduleNodeImpl::StopSchedule(ResultCode errorCode)
177 {
178 std::lock_guard<std::mutex> lock(mutex_);
179
180 SetFwkResultCode(errorCode);
181 IAM_LOGI("stop schedule %{public}s, error code %{public}d", GET_MASKED_STRING(info_.scheduleId).c_str(),
182 errorCode);
183 return TryKickMachine(E_STOP_AUTH);
184 }
185
SendMessage(ExecutorRole dstRole,const std::vector<uint8_t> & msg)186 bool ScheduleNodeImpl::SendMessage(ExecutorRole dstRole, const std::vector<uint8_t> &msg)
187 {
188 Attributes attr(msg);
189 if (dstRole == SCHEDULER) {
190 int32_t tip;
191 if (attr.GetInt32Value(Attributes::ATTR_TIP_INFO, tip)) {
192 std::shared_ptr<ScheduleNodeCallback> callback = GetScheduleCallback();
193 IF_FALSE_LOGE_AND_RETURN_VAL(callback != nullptr, false);
194 callback->OnScheduleProcessed(dstRole, GetAuthType(), msg);
195 return true;
196 } else {
197 int srcRole;
198 std::vector<uint8_t> message;
199 bool getAcquireRet = attr.GetInt32Value(Attributes::ATTR_SRC_ROLE, srcRole);
200 IF_FALSE_LOGE_AND_RETURN_VAL(getAcquireRet, false);
201 bool getExtraInfoRet = attr.GetUint8ArrayValue(Attributes::ATTR_EXTRA_INFO, message);
202 IF_FALSE_LOGE_AND_RETURN_VAL(getExtraInfoRet, false);
203 auto hdi = HdiWrapper::GetHdiInstance();
204 IF_FALSE_LOGE_AND_RETURN_VAL(hdi != nullptr, false);
205 int sendMsgRet = hdi->SendMessage(GetScheduleId(), srcRole, message);
206 IF_FALSE_LOGE_AND_RETURN_VAL(sendMsgRet == HDF_SUCCESS, false);
207 return true;
208 }
209 }
210
211 std::shared_ptr<ResourceNode> node = nullptr;
212 if (dstRole == ALL_IN_ONE || dstRole == VERIFIER) {
213 node = info_.verifier.lock();
214 } else if (dstRole == COLLECTOR) {
215 node = info_.collector.lock();
216 }
217
218 IF_FALSE_LOGE_AND_RETURN_VAL(node != nullptr, false);
219 node->SendData(GetScheduleId(), attr);
220 return true;
221 }
222
ContinueSchedule(ResultCode resultCode,const std::shared_ptr<Attributes> & finalResult)223 bool ScheduleNodeImpl::ContinueSchedule(ResultCode resultCode, const std::shared_ptr<Attributes> &finalResult)
224 {
225 std::lock_guard<std::mutex> lock(mutex_);
226 SetExecutorResultCode(resultCode);
227 SetScheduleResult(finalResult);
228 return TryKickMachine(E_SCHEDULE_RESULT_RECEIVED);
229 }
230
MakeFiniteStateMachine()231 std::shared_ptr<FiniteStateMachine> ScheduleNodeImpl::MakeFiniteStateMachine()
232 {
233 auto builder = FiniteStateMachine::Builder::New(GetDescription(), S_INIT);
234 if (builder == nullptr) {
235 return nullptr;
236 }
237 // S_INIT
238 builder->MakeTransition(S_INIT, E_START_AUTH, S_VERIFY_STARING,
239 [this](FiniteStateMachine &machine, uint32_t event) { ProcessBeginVerifier(machine, event); });
240
241 // S_VERIFY_STARING
242 builder->MakeTransition(S_VERIFY_STARING, E_VERIFY_STARTED_SUCCESS, S_COLLECT_STARING,
243 [this](FiniteStateMachine &machine, uint32_t event) { ProcessBeginCollector(machine, event); });
244 builder->MakeTransition(S_VERIFY_STARING, E_VERIFY_STARTED_FAILED, S_END,
245 [this](FiniteStateMachine &machine, uint32_t event) { ProcessVerifierBeginFailed(machine, event); });
246 builder->MakeTransition(S_VERIFY_STARING, E_SCHEDULE_RESULT_RECEIVED, S_END);
247 builder->MakeTransition(S_VERIFY_STARING, E_STOP_AUTH, S_VERIFY_STOPPING,
248 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
249 builder->MakeTransition(S_VERIFY_STARING, E_TIME_OUT, S_VERIFY_STOPPING,
250 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
251
252 // S_COLLECT_STARING
253 builder->MakeTransition(S_COLLECT_STARING, E_COLLECT_STARTED_SUCCESS, S_AUTH_PROCESSING);
254 builder->MakeTransition(S_COLLECT_STARING, E_SCHEDULE_RESULT_RECEIVED, S_END);
255 builder->MakeTransition(S_COLLECT_STARING, E_STOP_AUTH, S_COLLECT_STOPPING,
256 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
257
258 // S_AUTH_PROCESSING
259 builder->MakeTransition(S_AUTH_PROCESSING, E_SCHEDULE_RESULT_RECEIVED, S_END);
260 builder->MakeTransition(S_AUTH_PROCESSING, E_STOP_AUTH, S_COLLECT_STOPPING,
261 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
262 builder->MakeTransition(S_AUTH_PROCESSING, E_TIME_OUT, S_COLLECT_STOPPING,
263 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
264
265 // S_COLLECT_STOPPING
266 builder->MakeTransition(S_COLLECT_STOPPING, E_SCHEDULE_RESULT_RECEIVED, S_END);
267 builder->MakeTransition(S_COLLECT_STOPPING, E_COLLECT_STOPPED_SUCCESS, S_VERIFY_STOPPING,
268 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
269 builder->MakeTransition(S_COLLECT_STOPPING, E_COLLECT_STOPPED_FAILED, S_VERIFY_STOPPING,
270 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
271 builder->MakeTransition(S_COLLECT_STOPPING, E_TIME_OUT, S_VERIFY_STOPPING,
272 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
273
274 // S_VERIFY_STOPPING
275 builder->MakeTransition(S_VERIFY_STOPPING, E_SCHEDULE_RESULT_RECEIVED, S_END);
276 builder->MakeTransition(S_VERIFY_STOPPING, E_VERIFY_STOPPED_SUCCESS, S_END);
277 builder->MakeTransition(S_VERIFY_STOPPING, E_VERIFY_STOPPED_FAILED, S_END);
278 builder->MakeTransition(S_VERIFY_STOPPING, E_TIME_OUT, S_END);
279
280 // ENTERS
281 builder->MakeOnStateEnter(S_AUTH_PROCESSING,
282 [this](FiniteStateMachine &machine, uint32_t event) { OnScheduleProcessing(machine, event); });
283 builder->MakeOnStateEnter(S_END,
284 [this](FiniteStateMachine &machine, uint32_t event) { OnScheduleFinished(machine, event); });
285 return builder->Build();
286 }
287
GetDescription() const288 std::string ScheduleNodeImpl::GetDescription() const
289 {
290 std::ostringstream ss;
291
292 auto verifier = info_.verifier.lock();
293 ss << "schedule type:" << (verifier ? Common::AuthTypeToStr(verifier->GetAuthType()) : "nullptr") <<
294 " id:******" << std::hex << static_cast<uint16_t>(GetScheduleId());
295 return ss.str();
296 }
297
TryKickMachine(Event event)298 bool ScheduleNodeImpl::TryKickMachine(Event event)
299 {
300 if (machine_ == nullptr) {
301 return false;
302 }
303 machine_->Schedule(event);
304 return true;
305 }
306
SetFwkResultCode(int32_t resultCode)307 void ScheduleNodeImpl::SetFwkResultCode(int32_t resultCode)
308 {
309 fwkResultCode_ = resultCode;
310 }
311
SetExecutorResultCode(int32_t resultCode)312 void ScheduleNodeImpl::SetExecutorResultCode(int32_t resultCode)
313 {
314 executorResultCode_ = resultCode;
315 }
316
SetScheduleResult(const std::shared_ptr<Attributes> & scheduleResult)317 void ScheduleNodeImpl::SetScheduleResult(const std::shared_ptr<Attributes> &scheduleResult)
318 {
319 scheduleResult_ = scheduleResult;
320 }
321
StartTimer()322 void ScheduleNodeImpl::StartTimer()
323 {
324 std::lock_guard<std::mutex> lock(mutex_);
325 if (info_.expiredTime == 0 || timerId_ != 0) {
326 return;
327 }
328
329 timerId_ = RelativeTimer::GetInstance().Register(
330 [self = weak_from_this(), this] {
331 if (self.lock()) {
332 std::lock_guard<std::mutex> lock(mutex_);
333 SetFwkResultCode(TIMEOUT);
334 TryKickMachine(E_TIME_OUT);
335 }
336 },
337 info_.expiredTime);
338 }
339
StopTimer()340 void ScheduleNodeImpl::StopTimer()
341 {
342 std::lock_guard<std::mutex> lock(mutex_);
343 if (timerId_ == 0) {
344 return;
345 }
346 RelativeTimer::GetInstance().Unregister(timerId_);
347 timerId_ = 0;
348 }
349
ProcessBeginVerifier(FiniteStateMachine & machine,uint32_t event)350 void ScheduleNodeImpl::ProcessBeginVerifier(FiniteStateMachine &machine, uint32_t event)
351 {
352 auto collector = info_.collector.lock();
353 auto verifier = info_.verifier.lock();
354 if (collector == nullptr || verifier == nullptr) {
355 SetFwkResultCode(GENERAL_ERROR);
356 machine.Schedule(E_VERIFY_STARTED_FAILED);
357 IAM_LOGE("invalid resource");
358 return;
359 }
360 auto peerPk = collector->GetExecutorPublicKey();
361 Attributes attr;
362 GetScheduleAttribute(true, attr);
363 auto result = verifier->BeginExecute(info_.scheduleId, peerPk, attr);
364 if (result != SUCCESS) {
365 IAM_LOGE("start verify failed, result = %{public}d", result);
366 SetExecutorResultCode(result);
367 machine.Schedule(E_VERIFY_STARTED_FAILED);
368 return;
369 }
370 IAM_LOGI("start verify success");
371 machine.Schedule(E_VERIFY_STARTED_SUCCESS);
372 }
373
ProcessBeginCollector(FiniteStateMachine & machine,uint32_t event)374 void ScheduleNodeImpl::ProcessBeginCollector(FiniteStateMachine &machine, uint32_t event)
375 {
376 auto collector = info_.collector.lock();
377 auto verifier = info_.verifier.lock();
378 if (collector == nullptr || verifier == nullptr) {
379 SetFwkResultCode(GENERAL_ERROR);
380 machine.Schedule(E_COLLECT_STARTED_FAILED);
381 IAM_LOGE("invalid resource");
382 return;
383 }
384 if (collector == verifier) {
385 IAM_LOGI("all in one schedule, just wait the result");
386 machine.Schedule(E_COLLECT_STARTED_SUCCESS);
387 return;
388 }
389
390 auto peerPk = collector->GetExecutorPublicKey();
391 Attributes attr;
392 GetScheduleAttribute(false, attr);
393 auto result = collector->BeginExecute(info_.scheduleId, peerPk, attr);
394 if (result != SUCCESS) {
395 IAM_LOGE("start collect failed, result = %{public}d", result);
396 SetExecutorResultCode(result);
397 machine.Schedule(E_COLLECT_STARTED_FAILED);
398 return;
399 }
400 IAM_LOGI("start collect success");
401 machine.Schedule(E_COLLECT_STARTED_SUCCESS);
402 NotifyCollectorReady();
403 }
404
NotifyCollectorReady()405 void ScheduleNodeImpl::NotifyCollectorReady()
406 {
407 auto verifier = info_.verifier.lock();
408 if (verifier == nullptr) {
409 return;
410 }
411
412 Attributes attr;
413 bool setPropertyModeRet = attr.SetInt32Value(Attributes::ATTR_PROPERTY_MODE, PROPERTY_MODE_NOTIFY_COLLECTOR_READY);
414 IF_FALSE_LOGE_AND_RETURN(setPropertyModeRet);
415 bool setScheduleIdRet = attr.SetUint64Value(Attributes::ATTR_SCHEDULE_ID, GetScheduleId());
416 IF_FALSE_LOGE_AND_RETURN(setScheduleIdRet);
417
418 int32_t ret = verifier->SetProperty(attr);
419 if (ret != SUCCESS) {
420 IAM_LOGE("notify collector ready failed, result = %{public}d", ret);
421 }
422 }
423
ProcessVerifierBeginFailed(FiniteStateMachine & machine,uint32_t event)424 void ScheduleNodeImpl::ProcessVerifierBeginFailed(FiniteStateMachine &machine, uint32_t event)
425 {
426 // just do nothing
427 }
428
ProcessCollectorBeginFailed(FiniteStateMachine & machine,uint32_t event)429 void ScheduleNodeImpl::ProcessCollectorBeginFailed(FiniteStateMachine &machine, uint32_t event)
430 {
431 // just do nothing
432 }
433
ProcessScheduleResultReceived(FiniteStateMachine & machine,uint32_t event) const434 void ScheduleNodeImpl::ProcessScheduleResultReceived(FiniteStateMachine &machine, uint32_t event) const
435 {
436 // just do nothing
437 }
438
ProcessEndCollector(FiniteStateMachine & machine,uint32_t event)439 void ScheduleNodeImpl::ProcessEndCollector(FiniteStateMachine &machine, uint32_t event)
440 {
441 auto collector = info_.collector.lock();
442 auto verifier = info_.verifier.lock();
443 if (collector == nullptr || verifier == nullptr) {
444 SetFwkResultCode(GENERAL_ERROR);
445 machine.Schedule(E_COLLECT_STOPPED_FAILED);
446 return;
447 }
448 if (collector == verifier) {
449 IAM_LOGE("all in one schedule, just do noting");
450 machine.Schedule(E_COLLECT_STOPPED_SUCCESS);
451 return;
452 }
453 Attributes attr;
454 auto result = collector->EndExecute(info_.scheduleId, attr);
455 if (result != SUCCESS) {
456 IAM_LOGE("end verify failed, result = %{public}d", result);
457 SetExecutorResultCode(result);
458 machine.Schedule(E_COLLECT_STOPPED_FAILED);
459 return;
460 }
461 machine.Schedule(E_COLLECT_STOPPED_SUCCESS);
462 }
463
ProcessEndVerifier(FiniteStateMachine & machine,uint32_t event)464 void ScheduleNodeImpl::ProcessEndVerifier(FiniteStateMachine &machine, uint32_t event)
465 {
466 auto verifier = info_.verifier.lock();
467 if (verifier == nullptr) {
468 SetFwkResultCode(GENERAL_ERROR);
469 machine.Schedule(E_VERIFY_STOPPED_FAILED);
470 return;
471 }
472 Attributes attr;
473 auto result = verifier->EndExecute(info_.scheduleId, attr);
474 if (result != SUCCESS) {
475 IAM_LOGE("end verify failed, result = %{public}d", result);
476 SetExecutorResultCode(result);
477 machine.Schedule(E_VERIFY_STOPPED_FAILED);
478 return;
479 }
480 machine.Schedule(E_VERIFY_STOPPED_SUCCESS);
481 }
482
OnScheduleProcessing(FiniteStateMachine & machine,uint32_t event)483 void ScheduleNodeImpl::OnScheduleProcessing(FiniteStateMachine &machine, uint32_t event)
484 {
485 std::shared_ptr<ScheduleNodeCallback> callback = GetScheduleCallback();
486 if (!callback) {
487 return;
488 }
489 callback->OnScheduleStarted();
490 }
491
OnScheduleFinished(FiniteStateMachine & machine,uint32_t event)492 void ScheduleNodeImpl::OnScheduleFinished(FiniteStateMachine &machine, uint32_t event)
493 {
494 StopTimer();
495 std::shared_ptr<ScheduleNodeCallback> callback = GetScheduleCallback();
496 if (!callback) {
497 return;
498 }
499
500 iamHitraceHelper_ = nullptr;
501
502 int32_t result = fwkResultCode_.value_or(executorResultCode_);
503 IAM_LOGI("schedule result = %{public}d", result);
504 callback->OnScheduleStoped(result, scheduleResult_);
505 ClearScheduleCallback();
506 }
507 } // namespace UserAuth
508 } // namespace UserIam
509 } // namespace OHOS
510