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