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