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
ClearScheduleCallback()143 void ScheduleNodeImpl::ClearScheduleCallback()
144 {
145 std::lock_guard<std::mutex> lock(mutex_);
146 info_.callback = nullptr;
147 }
148
StartSchedule()149 bool ScheduleNodeImpl::StartSchedule()
150 {
151 iamHitraceHelper_ = Common::MakeShared<IamHitraceHelper>(GetDescription());
152 {
153 std::lock_guard<std::mutex> lock(mutex_);
154 resourceNodePoolListener_ = Common::MakeShared<ScheduleResourceNodeListener>(weak_from_this());
155 IF_FALSE_LOGE_AND_RETURN_VAL(resourceNodePoolListener_ != nullptr, false);
156 bool registerRet = ResourceNodePool::Instance().RegisterResourceNodePoolListener(resourceNodePoolListener_);
157 IF_FALSE_LOGE_AND_RETURN_VAL(registerRet, false);
158 if (!TryKickMachine(E_START_AUTH)) {
159 return false;
160 }
161 }
162 StartTimer();
163 return true;
164 }
165
StopSchedule()166 bool ScheduleNodeImpl::StopSchedule()
167 {
168 return StopSchedule(CANCELED);
169 }
170
StopSchedule(ResultCode errorCode)171 bool ScheduleNodeImpl::StopSchedule(ResultCode errorCode)
172 {
173 std::lock_guard<std::mutex> lock(mutex_);
174
175 SetFwkResultCode(errorCode);
176 IAM_LOGI("stop schedule %{public}s, error code %{public}d", GET_MASKED_STRING(info_.scheduleId).c_str(),
177 errorCode);
178 return TryKickMachine(E_STOP_AUTH);
179 }
180
SendMessage(ExecutorRole dstRole,const std::vector<uint8_t> & msg)181 bool ScheduleNodeImpl::SendMessage(ExecutorRole dstRole, const std::vector<uint8_t> &msg)
182 {
183 Attributes attr(msg);
184 if (dstRole == SCHEDULER) {
185 int32_t tip;
186 if (attr.GetInt32Value(Attributes::ATTR_TIP_INFO, tip)) {
187 std::shared_ptr<ScheduleNodeCallback> callback = GetScheduleCallback();
188 IF_FALSE_LOGE_AND_RETURN_VAL(callback != nullptr, false);
189 callback->OnScheduleProcessed(dstRole, GetAuthType(), msg);
190 return true;
191 } else {
192 int srcRole;
193 std::vector<uint8_t> message;
194 bool getAcquireRet = attr.GetInt32Value(Attributes::ATTR_SRC_ROLE, srcRole);
195 IF_FALSE_LOGE_AND_RETURN_VAL(getAcquireRet, false);
196 bool getExtraInfoRet = attr.GetUint8ArrayValue(Attributes::ATTR_EXTRA_INFO, message);
197 IF_FALSE_LOGE_AND_RETURN_VAL(getExtraInfoRet, false);
198 auto hdi = HdiWrapper::GetHdiInstance();
199 IF_FALSE_LOGE_AND_RETURN_VAL(hdi != nullptr, false);
200 int sendMsgRet = hdi->SendMessage(GetScheduleId(), srcRole, message);
201 IF_FALSE_LOGE_AND_RETURN_VAL(sendMsgRet == HDF_SUCCESS, false);
202 return true;
203 }
204 }
205
206 std::shared_ptr<ResourceNode> node = nullptr;
207 if (dstRole == ALL_IN_ONE || dstRole == VERIFIER) {
208 node = info_.verifier.lock();
209 } else if (dstRole == COLLECTOR) {
210 node = info_.collector.lock();
211 }
212
213 IF_FALSE_LOGE_AND_RETURN_VAL(node != nullptr, false);
214 node->SendData(GetScheduleId(), attr);
215 return true;
216 }
217
ContinueSchedule(ResultCode resultCode,const std::shared_ptr<Attributes> & finalResult)218 bool ScheduleNodeImpl::ContinueSchedule(ResultCode resultCode, const std::shared_ptr<Attributes> &finalResult)
219 {
220 std::lock_guard<std::mutex> lock(mutex_);
221 SetExecutorResultCode(resultCode);
222 SetScheduleResult(finalResult);
223 return TryKickMachine(E_SCHEDULE_RESULT_RECEIVED);
224 }
225
MakeFiniteStateMachine()226 std::shared_ptr<FiniteStateMachine> ScheduleNodeImpl::MakeFiniteStateMachine()
227 {
228 auto builder = FiniteStateMachine::Builder::New(GetDescription(), S_INIT);
229 if (builder == nullptr) {
230 return nullptr;
231 }
232 // S_INIT
233 builder->MakeTransition(S_INIT, E_START_AUTH, S_VERIFY_STARING,
234 [this](FiniteStateMachine &machine, uint32_t event) { ProcessBeginVerifier(machine, event); });
235
236 // S_VERIFY_STARING
237 builder->MakeTransition(S_VERIFY_STARING, E_VERIFY_STARTED_SUCCESS, S_COLLECT_STARING,
238 [this](FiniteStateMachine &machine, uint32_t event) { ProcessBeginCollector(machine, event); });
239 builder->MakeTransition(S_VERIFY_STARING, E_VERIFY_STARTED_FAILED, S_END,
240 [this](FiniteStateMachine &machine, uint32_t event) { ProcessVerifierBeginFailed(machine, event); });
241 builder->MakeTransition(S_VERIFY_STARING, E_SCHEDULE_RESULT_RECEIVED, S_END);
242 builder->MakeTransition(S_VERIFY_STARING, E_STOP_AUTH, S_VERIFY_STOPPING,
243 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
244 builder->MakeTransition(S_VERIFY_STARING, E_TIME_OUT, S_VERIFY_STOPPING,
245 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
246
247 // S_COLLECT_STARING
248 builder->MakeTransition(S_COLLECT_STARING, E_COLLECT_STARTED_SUCCESS, S_AUTH_PROCESSING);
249 builder->MakeTransition(S_COLLECT_STARING, E_SCHEDULE_RESULT_RECEIVED, S_END);
250 builder->MakeTransition(S_COLLECT_STARING, E_STOP_AUTH, S_COLLECT_STOPPING,
251 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
252
253 // S_AUTH_PROCESSING
254 builder->MakeTransition(S_AUTH_PROCESSING, E_SCHEDULE_RESULT_RECEIVED, S_END);
255 builder->MakeTransition(S_AUTH_PROCESSING, E_STOP_AUTH, S_COLLECT_STOPPING,
256 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
257 builder->MakeTransition(S_AUTH_PROCESSING, E_TIME_OUT, S_COLLECT_STOPPING,
258 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndCollector(machine, event); });
259
260 // S_COLLECT_STOPPING
261 builder->MakeTransition(S_COLLECT_STOPPING, E_SCHEDULE_RESULT_RECEIVED, S_END);
262 builder->MakeTransition(S_COLLECT_STOPPING, E_COLLECT_STOPPED_SUCCESS, S_VERIFY_STOPPING,
263 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
264 builder->MakeTransition(S_COLLECT_STOPPING, E_COLLECT_STOPPED_FAILED, S_VERIFY_STOPPING,
265 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
266 builder->MakeTransition(S_COLLECT_STOPPING, E_TIME_OUT, S_VERIFY_STOPPING,
267 [this](FiniteStateMachine &machine, uint32_t event) { ProcessEndVerifier(machine, event); });
268
269 // S_VERIFY_STOPPING
270 builder->MakeTransition(S_VERIFY_STOPPING, E_SCHEDULE_RESULT_RECEIVED, S_END);
271 builder->MakeTransition(S_VERIFY_STOPPING, E_VERIFY_STOPPED_SUCCESS, S_END);
272 builder->MakeTransition(S_VERIFY_STOPPING, E_VERIFY_STOPPED_FAILED, S_END);
273 builder->MakeTransition(S_VERIFY_STOPPING, E_TIME_OUT, S_END);
274
275 // ENTERS
276 builder->MakeOnStateEnter(S_AUTH_PROCESSING,
277 [this](FiniteStateMachine &machine, uint32_t event) { OnScheduleProcessing(machine, event); });
278 builder->MakeOnStateEnter(S_END,
279 [this](FiniteStateMachine &machine, uint32_t event) { OnScheduleFinished(machine, event); });
280 return builder->Build();
281 }
282
GetDescription() const283 std::string ScheduleNodeImpl::GetDescription() const
284 {
285 std::ostringstream ss;
286
287 auto verifier = info_.verifier.lock();
288 ss << "schedule type:" << (verifier ? Common::AuthTypeToStr(verifier->GetAuthType()) : "nullptr") <<
289 " id:******" << std::hex << static_cast<uint16_t>(GetScheduleId());
290 return ss.str();
291 }
292
TryKickMachine(Event event)293 bool ScheduleNodeImpl::TryKickMachine(Event event)
294 {
295 if (machine_ == nullptr) {
296 return false;
297 }
298 machine_->Schedule(event);
299 return true;
300 }
301
SetFwkResultCode(int32_t resultCode)302 void ScheduleNodeImpl::SetFwkResultCode(int32_t resultCode)
303 {
304 fwkResultCode_ = resultCode;
305 }
306
SetExecutorResultCode(int32_t resultCode)307 void ScheduleNodeImpl::SetExecutorResultCode(int32_t resultCode)
308 {
309 executorResultCode_ = resultCode;
310 }
311
SetScheduleResult(const std::shared_ptr<Attributes> & scheduleResult)312 void ScheduleNodeImpl::SetScheduleResult(const std::shared_ptr<Attributes> &scheduleResult)
313 {
314 scheduleResult_ = scheduleResult;
315 }
316
StartTimer()317 void ScheduleNodeImpl::StartTimer()
318 {
319 std::lock_guard<std::mutex> lock(mutex_);
320 if (info_.expiredTime == 0 || timerId_ != 0) {
321 return;
322 }
323
324 timerId_ = RelativeTimer::GetInstance().Register(
325 [self = weak_from_this(), this] {
326 if (self.lock()) {
327 std::lock_guard<std::mutex> lock(mutex_);
328 SetFwkResultCode(TIMEOUT);
329 TryKickMachine(E_TIME_OUT);
330 }
331 },
332 info_.expiredTime);
333 }
334
StopTimer()335 void ScheduleNodeImpl::StopTimer()
336 {
337 std::lock_guard<std::mutex> lock(mutex_);
338 if (timerId_ == 0) {
339 return;
340 }
341 RelativeTimer::GetInstance().Unregister(timerId_);
342 timerId_ = 0;
343 }
344
ProcessBeginVerifier(FiniteStateMachine & machine,uint32_t event)345 void ScheduleNodeImpl::ProcessBeginVerifier(FiniteStateMachine &machine, uint32_t event)
346 {
347 auto collector = info_.collector.lock();
348 auto verifier = info_.verifier.lock();
349 if (collector == nullptr || verifier == nullptr) {
350 SetFwkResultCode(GENERAL_ERROR);
351 machine.Schedule(E_VERIFY_STARTED_FAILED);
352 IAM_LOGE("invalid resource");
353 return;
354 }
355 auto peerPk = collector->GetExecutorPublicKey();
356 Attributes attr;
357 GetScheduleAttribute(true, attr);
358 auto result = verifier->BeginExecute(info_.scheduleId, peerPk, attr);
359 if (result != SUCCESS) {
360 IAM_LOGE("start verify failed, result = %{public}d", result);
361 SetExecutorResultCode(result);
362 machine.Schedule(E_VERIFY_STARTED_FAILED);
363 return;
364 }
365 IAM_LOGI("start verify success");
366 machine.Schedule(E_VERIFY_STARTED_SUCCESS);
367 }
368
ProcessBeginCollector(FiniteStateMachine & machine,uint32_t event)369 void ScheduleNodeImpl::ProcessBeginCollector(FiniteStateMachine &machine, uint32_t event)
370 {
371 auto collector = info_.collector.lock();
372 auto verifier = info_.verifier.lock();
373 if (collector == nullptr || verifier == nullptr) {
374 SetFwkResultCode(GENERAL_ERROR);
375 machine.Schedule(E_COLLECT_STARTED_FAILED);
376 IAM_LOGE("invalid resource");
377 return;
378 }
379 if (collector == verifier) {
380 IAM_LOGI("all in one schedule, just wait the result");
381 machine.Schedule(E_COLLECT_STARTED_SUCCESS);
382 return;
383 }
384
385 auto peerPk = collector->GetExecutorPublicKey();
386 Attributes attr;
387 GetScheduleAttribute(false, attr);
388 auto result = collector->BeginExecute(info_.scheduleId, peerPk, attr);
389 if (result != SUCCESS) {
390 IAM_LOGE("start collect failed, result = %{public}d", result);
391 SetExecutorResultCode(result);
392 machine.Schedule(E_COLLECT_STARTED_FAILED);
393 return;
394 }
395 IAM_LOGI("start collect success");
396 machine.Schedule(E_COLLECT_STARTED_SUCCESS);
397 NotifyCollectorReady();
398 }
399
NotifyCollectorReady()400 void ScheduleNodeImpl::NotifyCollectorReady()
401 {
402 auto verifier = info_.verifier.lock();
403 if (verifier == nullptr) {
404 return;
405 }
406
407 Attributes attr;
408 bool setPropertyModeRet = attr.SetInt32Value(Attributes::ATTR_PROPERTY_MODE, PROPERTY_MODE_NOTIFY_COLLECTOR_READY);
409 IF_FALSE_LOGE_AND_RETURN(setPropertyModeRet);
410 bool setScheduleIdRet = attr.SetUint64Value(Attributes::ATTR_SCHEDULE_ID, GetScheduleId());
411 IF_FALSE_LOGE_AND_RETURN(setScheduleIdRet);
412
413 int32_t ret = verifier->SetProperty(attr);
414 if (ret != SUCCESS) {
415 IAM_LOGE("notify collector ready failed, result = %{public}d", ret);
416 }
417 }
418
ProcessVerifierBeginFailed(FiniteStateMachine & machine,uint32_t event)419 void ScheduleNodeImpl::ProcessVerifierBeginFailed(FiniteStateMachine &machine, uint32_t event)
420 {
421 // just do nothing
422 }
423
ProcessCollectorBeginFailed(FiniteStateMachine & machine,uint32_t event)424 void ScheduleNodeImpl::ProcessCollectorBeginFailed(FiniteStateMachine &machine, uint32_t event)
425 {
426 // just do nothing
427 }
428
ProcessScheduleResultReceived(FiniteStateMachine & machine,uint32_t event) const429 void ScheduleNodeImpl::ProcessScheduleResultReceived(FiniteStateMachine &machine, uint32_t event) const
430 {
431 // just do nothing
432 }
433
ProcessEndCollector(FiniteStateMachine & machine,uint32_t event)434 void ScheduleNodeImpl::ProcessEndCollector(FiniteStateMachine &machine, uint32_t event)
435 {
436 auto collector = info_.collector.lock();
437 auto verifier = info_.verifier.lock();
438 if (collector == nullptr || verifier == nullptr) {
439 SetFwkResultCode(GENERAL_ERROR);
440 machine.Schedule(E_COLLECT_STOPPED_FAILED);
441 return;
442 }
443 if (collector == verifier) {
444 IAM_LOGE("all in one schedule, just do noting");
445 machine.Schedule(E_COLLECT_STOPPED_SUCCESS);
446 return;
447 }
448 Attributes attr;
449 auto result = collector->EndExecute(info_.scheduleId, attr);
450 if (result != SUCCESS) {
451 IAM_LOGE("end verify failed, result = %{public}d", result);
452 SetExecutorResultCode(result);
453 machine.Schedule(E_COLLECT_STOPPED_FAILED);
454 return;
455 }
456 machine.Schedule(E_COLLECT_STOPPED_SUCCESS);
457 }
458
ProcessEndVerifier(FiniteStateMachine & machine,uint32_t event)459 void ScheduleNodeImpl::ProcessEndVerifier(FiniteStateMachine &machine, uint32_t event)
460 {
461 auto verifier = info_.verifier.lock();
462 if (verifier == nullptr) {
463 SetFwkResultCode(GENERAL_ERROR);
464 machine.Schedule(E_VERIFY_STOPPED_FAILED);
465 return;
466 }
467 Attributes attr;
468 auto result = verifier->EndExecute(info_.scheduleId, attr);
469 if (result != SUCCESS) {
470 IAM_LOGE("end verify failed, result = %{public}d", result);
471 SetExecutorResultCode(result);
472 machine.Schedule(E_VERIFY_STOPPED_FAILED);
473 return;
474 }
475 machine.Schedule(E_VERIFY_STOPPED_SUCCESS);
476 }
477
OnScheduleProcessing(FiniteStateMachine & machine,uint32_t event)478 void ScheduleNodeImpl::OnScheduleProcessing(FiniteStateMachine &machine, uint32_t event)
479 {
480 std::shared_ptr<ScheduleNodeCallback> callback = GetScheduleCallback();
481 if (!callback) {
482 return;
483 }
484 callback->OnScheduleStarted();
485 }
486
OnScheduleFinished(FiniteStateMachine & machine,uint32_t event)487 void ScheduleNodeImpl::OnScheduleFinished(FiniteStateMachine &machine, uint32_t event)
488 {
489 StopTimer();
490 std::shared_ptr<ScheduleNodeCallback> callback = GetScheduleCallback();
491 if (!callback) {
492 return;
493 }
494
495 iamHitraceHelper_ = nullptr;
496
497 int32_t result = fwkResultCode_.value_or(executorResultCode_);
498 IAM_LOGI("schedule result = %{public}d", result);
499 callback->OnScheduleStoped(result, scheduleResult_);
500 ClearScheduleCallback();
501 }
502 } // namespace UserAuth
503 } // namespace UserIam
504 } // namespace OHOS
505