1 /*
2 * Copyright (c) 2024 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
16 #include "startup_task_dispatcher.h"
17
18 #include "event_handler.h"
19 #include "hilog_tag_wrapper.h"
20 #include "startup_manager.h"
21
22 namespace OHOS {
23 namespace AbilityRuntime {
StartupTaskDispatcher(const std::map<std::string,std::shared_ptr<StartupTask>> & tasks,const std::shared_ptr<StartupSortResult> & sortResult)24 StartupTaskDispatcher::StartupTaskDispatcher(const std::map<std::string, std::shared_ptr<StartupTask>> &tasks,
25 const std::shared_ptr<StartupSortResult> &sortResult) : tasks_(tasks), sortResult_(sortResult)
26 {}
27
~StartupTaskDispatcher()28 StartupTaskDispatcher::~StartupTaskDispatcher()
29 {
30 TAG_LOGD(AAFwkTag::STARTUP, "deconstruct");
31 }
32
Run(const std::shared_ptr<OnCompletedCallback> & completedCallback,const std::shared_ptr<OnCompletedCallback> & mainThreadAwaitCallback)33 int32_t StartupTaskDispatcher::Run(const std::shared_ptr<OnCompletedCallback> &completedCallback,
34 const std::shared_ptr<OnCompletedCallback> &mainThreadAwaitCallback)
35 {
36 if (sortResult_ == nullptr) {
37 TAG_LOGE(AAFwkTag::STARTUP, "sortResult null");
38 return ERR_STARTUP_INTERNAL_ERROR;
39 }
40 for (auto &iter : tasks_) {
41 if (iter.second == nullptr) {
42 TAG_LOGE(AAFwkTag::STARTUP, "startup task %{public}s null", iter.first.c_str());
43 return ERR_STARTUP_INTERNAL_ERROR;
44 }
45 inDegreeMap_.emplace(iter.first, iter.second->getDependenciesCount());
46 if (iter.second->GetWaitOnMainThread()) {
47 mainThreadAwaitCount_++;
48 }
49 }
50 tasksCount_ = tasks_.size();
51 completedCallback_ = completedCallback;
52 mainThreadAwaitCallback_ = mainThreadAwaitCallback;
53
54 if (mainThreadAwaitCount_ == 0) {
55 TAG_LOGD(AAFwkTag::STARTUP, "no main thread await task");
56 if (mainThreadAwaitCallback_ != nullptr) {
57 auto result = std::make_shared<StartupTaskResult>();
58 mainThreadAwaitCallback_->Call(result);
59 }
60 }
61
62 for (auto &iter : sortResult_->zeroDequeResult_) {
63 auto findResult = tasks_.find(iter);
64 if (findResult == tasks_.end()) {
65 TAG_LOGE(AAFwkTag::STARTUP, "startup task not found %{public}s", iter.c_str());
66 return ERR_STARTUP_INTERNAL_ERROR;
67 }
68 if (findResult->second == nullptr) {
69 TAG_LOGE(AAFwkTag::STARTUP, "startup task %{public}s null", iter.c_str());
70 return ERR_STARTUP_INTERNAL_ERROR;
71 }
72 int32_t result = RunTaskInit(iter, findResult->second);
73 if (result != ERR_OK) {
74 return result;
75 }
76 }
77 return ERR_OK;
78 }
79
Dispatch(const std::string & name,const std::shared_ptr<StartupTaskResult> & result)80 void StartupTaskDispatcher::Dispatch(const std::string &name, const std::shared_ptr<StartupTaskResult> &result)
81 {
82 TAG_LOGD(AAFwkTag::STARTUP, "run startup task %{public}s dispatch", name.c_str());
83 if (result == nullptr) {
84 OnError(ERR_STARTUP_INTERNAL_ERROR, name + ": result is null");
85 return;
86 }
87 if (result->GetResultCode() != ERR_OK) {
88 OnError(name, result);
89 return;
90 }
91 auto findResult = tasks_.find(name);
92 if (findResult == tasks_.end() || findResult->second == nullptr) {
93 OnError(ERR_STARTUP_INTERNAL_ERROR, name + " not found");
94 return;
95 }
96 if (NotifyChildren(name, result) != ERR_OK) {
97 return;
98 }
99
100 if (findResult->second->GetWaitOnMainThread()) {
101 mainThreadAwaitCount_--;
102 TAG_LOGD(AAFwkTag::STARTUP, "mainThreadAwaitCount %{public}d", mainThreadAwaitCount_);
103 if (mainThreadAwaitCount_ == 0) {
104 if (mainThreadAwaitCallback_ != nullptr) {
105 mainThreadAwaitCallback_->Call(result);
106 }
107 }
108 }
109 tasksCount_--;
110 TAG_LOGD(AAFwkTag::STARTUP, "tasksCount %{public}d", tasksCount_);
111 if (tasksCount_ == 0) {
112 if (completedCallback_ != nullptr) {
113 completedCallback_->Call(result);
114 }
115 }
116 }
117
NotifyChildren(const std::string & name,const std::shared_ptr<StartupTaskResult> & result)118 int32_t StartupTaskDispatcher::NotifyChildren(const std::string &name, const std::shared_ptr<StartupTaskResult> &result)
119 {
120 if (sortResult_ == nullptr) {
121 OnError(ERR_STARTUP_INTERNAL_ERROR, name + ": sort result is null");
122 return ERR_STARTUP_INTERNAL_ERROR;
123 }
124 auto findResult = sortResult_->startupChildrenMap_.find(name);
125 if (findResult == sortResult_->startupChildrenMap_.end()) {
126 OnError(ERR_STARTUP_INTERNAL_ERROR, name + " is not found");
127 return ERR_STARTUP_INTERNAL_ERROR;
128 }
129 std::vector<std::shared_ptr<StartupTask>> zeroInDegree;
130 for (auto &child : findResult->second) {
131 auto childFindResult = inDegreeMap_.find(child);
132 if (childFindResult == inDegreeMap_.end()) {
133 OnError(ERR_STARTUP_INTERNAL_ERROR, child + "is not found in inDegreeMap_.");
134 return ERR_STARTUP_INTERNAL_ERROR;
135 }
136 auto childStartupTask = tasks_.find(child);
137 if (childStartupTask == tasks_.end()) {
138 OnError(ERR_STARTUP_INTERNAL_ERROR, child + "is not found in tasks_.");
139 return ERR_STARTUP_INTERNAL_ERROR;
140 }
141 if (childStartupTask->second == nullptr) {
142 OnError(ERR_STARTUP_INTERNAL_ERROR, child + " task is null.");
143 return ERR_STARTUP_INTERNAL_ERROR;
144 }
145 childStartupTask->second->RunTaskOnDependencyCompleted(name, result);
146 childFindResult->second--;
147 if (childFindResult->second == 0) {
148 zeroInDegree.emplace_back(childStartupTask->second);
149 }
150 }
151 for (auto &iter : zeroInDegree) {
152 int32_t runResult = RunTaskInit(iter->GetName(), iter);
153 if (runResult != ERR_OK) {
154 return runResult;
155 }
156 }
157 return ERR_OK;
158 }
159
RunTaskInit(const std::string & name,const std::shared_ptr<StartupTask> & task)160 int32_t StartupTaskDispatcher::RunTaskInit(const std::string &name, const std::shared_ptr<StartupTask> &task)
161 {
162 TAG_LOGD(AAFwkTag::STARTUP, "%{public}s init", name.c_str());
163 std::unique_ptr<StartupTaskResultCallback> callback = std::make_unique<StartupTaskResultCallback>();
164 callback->Push([weak = weak_from_this(), name](const std::shared_ptr<StartupTaskResult> &result) {
165 auto startupTaskDispatcher = weak.lock();
166 if (startupTaskDispatcher == nullptr) {
167 TAG_LOGD(AAFwkTag::STARTUP, "startupTaskDispatcher may have been release due to previous error");
168 return;
169 }
170 startupTaskDispatcher->Dispatch(name, result);
171 });
172 StartupTask::State state = task->GetState();
173 if (state == StartupTask::State::CREATED) {
174 return task->RunTaskInit(std::move(callback));
175 } else if (state == StartupTask::State::INITIALIZED) {
176 callback->Call(task->GetResult());
177 return ERR_OK;
178 } else if (state == StartupTask::State::INITIALIZING) {
179 return task->AddExtraCallback(std::move(callback));
180 } else {
181 // state: INVALID
182 TAG_LOGE(AAFwkTag::STARTUP, "%{public}s task state: INVALID", name.c_str());
183 return ERR_STARTUP_INTERNAL_ERROR;
184 }
185 }
186
OnError(const std::string & name,const std::shared_ptr<StartupTaskResult> & result)187 void StartupTaskDispatcher::OnError(const std::string &name, const std::shared_ptr<StartupTaskResult> &result)
188 {
189 TAG_LOGE(AAFwkTag::STARTUP, "%{public}s failed, %{public}d", name.c_str(), result->GetResultCode());
190 std::string resultMessage = name + ": " + result->GetResultMessage();
191 result->SetResultMessage(resultMessage);
192 if (completedCallback_ != nullptr) {
193 completedCallback_->Call(result);
194 }
195 DelayedSingleton<StartupManager>::GetInstance()->PostMainThreadTask(
196 [mainThreadAwaitCallback = mainThreadAwaitCallback_, result]() {
197 if (mainThreadAwaitCallback != nullptr) {
198 mainThreadAwaitCallback->Call(result);
199 }
200 });
201 }
202
OnError(int32_t errorCode,const std::string & errorMessage)203 void StartupTaskDispatcher::OnError(int32_t errorCode, const std::string &errorMessage)
204 {
205 TAG_LOGE(AAFwkTag::STARTUP, "%{public}s", errorMessage.c_str());
206 auto result = std::make_shared<StartupTaskResult>(errorCode, errorMessage);
207 if (completedCallback_ != nullptr) {
208 completedCallback_->Call(result);
209 }
210 DelayedSingleton<StartupManager>::GetInstance()->PostMainThreadTask(
211 [mainThreadAwaitCallback = mainThreadAwaitCallback_, result]() {
212 if (mainThreadAwaitCallback != nullptr) {
213 mainThreadAwaitCallback->Call(result);
214 }
215 });
216 }
217 } // namespace AbilityRuntime
218 } // namespace OHOS
219