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_manager.h"
17 
18 #include "hilog_tag_wrapper.h"
19 #include "startup_manager.h"
20 #include "startup_topologysort.h"
21 
22 namespace OHOS {
23 namespace AbilityRuntime {
StartupTaskManager(uint32_t startupTaskManagerId,std::map<std::string,std::shared_ptr<StartupTask>> tasks)24 StartupTaskManager::StartupTaskManager(uint32_t startupTaskManagerId,
25     std::map<std::string, std::shared_ptr<StartupTask>> tasks)
26     : startupTaskManagerId_(startupTaskManagerId), tasks_(std::move(tasks))
27 {}
28 
~StartupTaskManager()29 StartupTaskManager::~StartupTaskManager()
30 {
31     TAG_LOGD(AAFwkTag::STARTUP, "id: %{public}u deconstruct", startupTaskManagerId_);
32 }
33 
AddTask(const std::shared_ptr<StartupTask> & task)34 int32_t StartupTaskManager::AddTask(const std::shared_ptr<StartupTask> &task)
35 {
36     if (task == nullptr) {
37         TAG_LOGE(AAFwkTag::STARTUP, "Invalid task");
38         return ERR_STARTUP_INVALID_VALUE;
39     }
40     std::string name = task->GetName();
41     auto result = tasks_.emplace(name, task);
42     if (!result.second) {
43         TAG_LOGE(AAFwkTag::STARTUP, "%{public}s exist", name.c_str());
44         return ERR_STARTUP_INVALID_VALUE;
45     }
46     return ERR_OK;
47 }
48 
SetConfig(const std::shared_ptr<StartupConfig> & config)49 void StartupTaskManager::SetConfig(const std::shared_ptr<StartupConfig> &config)
50 {
51     config_ = config;
52 }
53 
Prepare()54 int32_t StartupTaskManager::Prepare()
55 {
56     TAG_LOGD(AAFwkTag::STARTUP, "id: %{public}u, task number: %{public}zu", startupTaskManagerId_, tasks_.size());
57     std::shared_ptr<StartupSortResult> startupSortResult = nullptr;
58     int32_t result = StartupTopologySort::Sort(tasks_, startupSortResult);
59     if (result != ERR_OK) {
60         CallListenerOnCompleted(result);
61         return result;
62     }
63     if (startupSortResult == nullptr) {
64         TAG_LOGE(AAFwkTag::STARTUP, "startupSortResult null");
65         CallListenerOnCompleted(ERR_STARTUP_INTERNAL_ERROR);
66         return ERR_STARTUP_INTERNAL_ERROR;
67     }
68     if (tasks_.empty()) {
69         TAG_LOGE(AAFwkTag::STARTUP, "no tasks");
70         return ERR_STARTUP_INTERNAL_ERROR;
71     }
72     dispatcher_ = std::make_shared<StartupTaskDispatcher>(tasks_, startupSortResult);
73     return ERR_OK;
74 }
75 
Run(const std::shared_ptr<OnCompletedCallback> & mainThreadAwaitCallback)76 int32_t StartupTaskManager::Run(const std::shared_ptr<OnCompletedCallback> &mainThreadAwaitCallback)
77 {
78     TAG_LOGD(AAFwkTag::STARTUP, "id: %{public}u, task number: %{public}zu", startupTaskManagerId_, tasks_.size());
79     if (dispatcher_ == nullptr) {
80         TAG_LOGE(AAFwkTag::STARTUP, "dispatcher null");
81         CallListenerOnCompleted(ERR_STARTUP_INTERNAL_ERROR);
82         return ERR_STARTUP_INTERNAL_ERROR;
83     }
84     AddAsyncTimeoutTimer();
85     auto completedCallback = std::make_shared<OnCompletedCallback>(
86         [weak = weak_from_this()](const std::shared_ptr<StartupTaskResult> &result) {
87             auto startupTaskManager = weak.lock();
88             if (startupTaskManager == nullptr) {
89                 TAG_LOGE(AAFwkTag::STARTUP, "startupTaskManager null");
90                 return;
91             }
92             startupTaskManager->CancelAsyncTimeoutTimer();
93             if (result == nullptr) {
94                 TAG_LOGE(AAFwkTag::STARTUP, "result null");
95                 return;
96             }
97             startupTaskManager->CallListenerOnCompleted(result->GetResultCode(), result->GetResultMessage());
98         });
99 
100     int32_t result = dispatcher_->Run(completedCallback, mainThreadAwaitCallback);
101     if (result != ERR_OK) {
102         CancelAsyncTimeoutTimer();
103         if (!completedCallback->IsCalled()) {
104             CallListenerOnCompleted(result);
105         }
106         return result;
107     }
108     return ERR_OK;
109 }
110 
CallListenerOnCompleted(int32_t result,const std::string & resultMessage)111 void StartupTaskManager::CallListenerOnCompleted(int32_t result, const std::string &resultMessage)
112 {
113     if (config_ == nullptr) {
114         TAG_LOGI(AAFwkTag::STARTUP,
115             "id: %{public}u, config is null, result: %{public}d", startupTaskManagerId_, result);
116         return;
117     }
118     TAG_LOGD(AAFwkTag::STARTUP, "id: %{public}u, complete, result: %{public}d", startupTaskManagerId_, result);
119     if (resultMessage.empty()) {
120         auto startupTaskResult = std::make_shared<StartupTaskResult>(result, StartupUtils::GetErrorMessage(result));
121         config_->ListenerOnCompleted(startupTaskResult);
122     } else {
123         auto startupTaskResult = std::make_shared<StartupTaskResult>(result, resultMessage);
124         config_->ListenerOnCompleted(startupTaskResult);
125     }
126     DelayedSingleton<StartupManager>::GetInstance()->OnStartupTaskManagerComplete(startupTaskManagerId_);
127 }
128 
AddAsyncTimeoutTimer()129 void StartupTaskManager::AddAsyncTimeoutTimer()
130 {
131     mainHandler_ = std::make_shared<AppExecFwk::EventHandler>(AppExecFwk::EventRunner::GetMainEventRunner());
132     if (mainHandler_ == nullptr) {
133         TAG_LOGE(AAFwkTag::STARTUP, "get mainHandler failed");
134         return;
135     }
136     int32_t timeoutMs = StartupConfig::DEFAULT_AWAIT_TIMEOUT_MS;
137     if (config_ != nullptr) {
138         timeoutMs = config_->GetAwaitTimeoutMs();
139     }
140     TAG_LOGD(AAFwkTag::STARTUP, "id: %{public}d, add timeout timer: %{public}d", startupTaskManagerId_, timeoutMs);
141     auto callback = [weak = weak_from_this()]() {
142         auto startupTaskManager = weak.lock();
143         if (startupTaskManager == nullptr) {
144             TAG_LOGE(AAFwkTag::STARTUP, "startupTaskManager null");
145             return;
146         }
147         startupTaskManager->OnTimeout();
148     };
149     mainHandler_->PostTask(callback, "StartupTaskManager_" + std::to_string(startupTaskManagerId_), timeoutMs);
150 }
151 
CancelAsyncTimeoutTimer()152 void StartupTaskManager::CancelAsyncTimeoutTimer()
153 {
154     if (mainHandler_ == nullptr) {
155         TAG_LOGE(AAFwkTag::STARTUP, "get mainHandler failed");
156         return;
157     }
158     TAG_LOGD(AAFwkTag::STARTUP, "id: %{public}d, cancel timeout timer", startupTaskManagerId_);
159     mainHandler_->RemoveTask("StartupTaskManager_" + std::to_string(startupTaskManagerId_));
160 }
161 
OnTimeout()162 void StartupTaskManager::OnTimeout()
163 {
164     CallListenerOnCompleted(ERR_STARTUP_TIMEOUT, StartupUtils::GetErrorMessage(ERR_STARTUP_TIMEOUT));
165     DelayedSingleton<StartupManager>::GetInstance()->OnStartupTaskManagerComplete(startupTaskManagerId_);
166 }
167 } // namespace AbilityRuntime
168 } // namespace OHOS
169