1 /*
2 * Copyright (c) 2025 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 "ext_native_startup_manager.h"
17
18 #include <dirent.h>
19 #include <dlfcn.h>
20
21 #include "ffrt.h"
22 #include "hilog_tag_wrapper.h"
23 #include "startup_task_manager.h"
24 #include "startup_manager.h"
25 #include "string_ex.h"
26
27 namespace OHOS {
28 namespace AbilityRuntime {
29 namespace {
30 #ifdef APP_USE_ARM64
31 constexpr char NATIVE_STARTUP_TASK_DIR[] = "system/lib64/nativestartuptask";
32 #elif defined(APP_USE_X86_64)
33 constexpr char NATIVE_STARTUP_TASK_DIR[] = "system/lib64/nativestartuptask";
34 #else
35 constexpr char NATIVE_STARTUP_TASK_DIR[] = "system/lib/nativestartuptask";
36 #endif
37 constexpr char PATH_SEPARATOR[] = "/";
38 constexpr char LIB_TYPE[] = ".so";
39 constexpr char LOAD_TASK_ENTRY[] = "OnLoadExtNativeStartupTask";
40 using LoadTaskFunc = void(*)();
41
42 class ExtNativeStartupTaskWrapper : public StartupTask {
43 public:
ExtNativeStartupTaskWrapper(const std::string & name,const std::shared_ptr<ExtNativeStartupTask> & extNativeStartupTask_)44 explicit ExtNativeStartupTaskWrapper(const std::string &name,
45 const std::shared_ptr<ExtNativeStartupTask> &extNativeStartupTask_)
46 : StartupTask(name), extNativeStartupTask_(extNativeStartupTask_)
47 {
48 }
49
50 ~ExtNativeStartupTaskWrapper() override = default;
51
GetType() const52 const std::string &GetType() const override
53 {
54 return name_;
55 }
56
RunTaskInit(std::unique_ptr<StartupTaskResultCallback> callback)57 int32_t RunTaskInit(std::unique_ptr<StartupTaskResultCallback> callback) override
58 {
59 callback_ = std::move(callback);
60 auto self = std::static_pointer_cast<ExtNativeStartupTaskWrapper>(shared_from_this());
61 auto runTaskInitCallback = [weak = std::weak_ptr(self)]() {
62 auto self = weak.lock();
63 if (self == nullptr) {
64 TAG_LOGE(AAFwkTag::STARTUP, "null self");
65 return;
66 }
67 self->RunTaskInitInner();
68 };
69 ffrt::submit(runTaskInitCallback);
70 return ERR_OK;
71 }
72
RunTaskOnDependencyCompleted(const std::string & dependencyName,const std::shared_ptr<StartupTaskResult> & result)73 int32_t RunTaskOnDependencyCompleted(const std::string &dependencyName,
74 const std::shared_ptr<StartupTaskResult> &result) override
75 {
76 // no onDependencyCompleted callback, do nothing
77 return ERR_OK;
78 }
79
80 private:
81 std::shared_ptr<ExtNativeStartupTask> extNativeStartupTask_;
82 std::unique_ptr<StartupTaskResultCallback> callback_;
83
RunTaskInitInner()84 void RunTaskInitInner()
85 {
86 TAG_LOGD(AAFwkTag::STARTUP, "run ext native task: %{public}s", name_.c_str());
87 if (extNativeStartupTask_ == nullptr) {
88 TAG_LOGE(AAFwkTag::STARTUP, "null extNativeStartupTask");
89 OnCompletedCallback::OnCallback(std::move(callback_), ERR_STARTUP_INTERNAL_ERROR);
90 return;
91 }
92 int32_t code = extNativeStartupTask_->RunTask();
93 if (code != ERR_OK) {
94 // the failure of the ext startup task does not affect other tasks
95 TAG_LOGE(AAFwkTag::STARTUP, "ext startup task %{public}s return %{public}d", name_.c_str(), code);
96 }
97 OnCompletedCallback::OnCallback(std::move(callback_), ERR_OK);
98 }
99 };
100
CheckFileType(const std::string & fileName,const std::string & suffix)101 bool CheckFileType(const std::string &fileName, const std::string &suffix)
102 {
103 if (fileName.empty()) {
104 TAG_LOGE(AAFwkTag::STARTUP, "file name empty");
105 return false;
106 }
107
108 auto position = fileName.rfind('.');
109 if (position == std::string::npos) {
110 TAG_LOGW(AAFwkTag::STARTUP, "filename no extension name");
111 return false;
112 }
113
114 std::string suffixStr = fileName.substr(position);
115 return LowerStr(suffixStr) == suffix;
116 }
117
ScanExtStartupTask(std::vector<std::string> & files)118 void ScanExtStartupTask(std::vector<std::string> &files)
119 {
120 std::string dirPath = NATIVE_STARTUP_TASK_DIR;
121 DIR *dirp = opendir(dirPath.c_str());
122 if (dirp == nullptr) {
123 TAG_LOGD(AAFwkTag::STARTUP, "no ext native startup task");
124 return;
125 }
126
127 struct dirent *dirf = nullptr;
128 for (;;) {
129 dirf = readdir(dirp);
130 if (dirf == nullptr) {
131 break;
132 }
133
134 std::string currentName(dirf->d_name);
135 if (currentName == "." || currentName == "..") {
136 continue;
137 }
138
139 if (CheckFileType(currentName, LIB_TYPE)) {
140 files.emplace_back(dirPath + PATH_SEPARATOR + currentName);
141 }
142 }
143
144 if (closedir(dirp) == -1) {
145 TAG_LOGW(AAFwkTag::STARTUP, "close dir fail");
146 }
147 }
148 } // namespace
149 ExtNativeStartupManager::ExtNativeStartupManager() = default;
150
151 ExtNativeStartupManager::~ExtNativeStartupManager() = default;
152
GetInstance()153 ExtNativeStartupManager &ExtNativeStartupManager::GetInstance()
154 {
155 static ExtNativeStartupManager instance;
156 return instance;
157 }
158
LoadExtStartupTask()159 void ExtNativeStartupManager::LoadExtStartupTask()
160 {
161 TAG_LOGD(AAFwkTag::STARTUP, "call");
162 std::vector<std::string> files;
163 ScanExtStartupTask(files);
164 for (auto& file : files) {
165 TAG_LOGD(AAFwkTag::STARTUP, "load file: %{public}s", file.c_str());
166 char resolvedFile[PATH_MAX] = {0};
167 if (realpath(file.c_str(), resolvedFile) == nullptr) {
168 TAG_LOGE(AAFwkTag::STARTUP, "invalid file path: %{public}s", file.c_str());
169 continue;
170 }
171 void* handle = dlopen(resolvedFile, RTLD_LAZY);
172 if (handle == nullptr) {
173 TAG_LOGE(AAFwkTag::STARTUP, "open %{public}s failed, reason: %{public}s", file.c_str(), dlerror());
174 continue;
175 }
176 auto loadTaskFunc = reinterpret_cast<LoadTaskFunc>(dlsym(handle, LOAD_TASK_ENTRY));
177 if (loadTaskFunc == nullptr) {
178 dlclose(handle);
179 TAG_LOGE(AAFwkTag::STARTUP, "failed to get symbol %{public}s in %{public}s", LOAD_TASK_ENTRY, file.c_str());
180 continue;
181 }
182 loadTaskFunc();
183 }
184 }
185
BuildExtStartupTask(const std::shared_ptr<ExtNativeStartupTask> & extNativeStartupTask,std::shared_ptr<StartupTask> & startupTask)186 int32_t ExtNativeStartupManager::BuildExtStartupTask(const std::shared_ptr<ExtNativeStartupTask> &extNativeStartupTask,
187 std::shared_ptr<StartupTask> &startupTask)
188 {
189 if (extNativeStartupTask == nullptr) {
190 TAG_LOGE(AAFwkTag::STARTUP, "null extNativeStartupTask");
191 return ERR_STARTUP_INVALID_VALUE;
192 }
193 startupTask = std::make_shared<ExtNativeStartupTaskWrapper>(extNativeStartupTask->GetName(), extNativeStartupTask);
194 startupTask->SetCallCreateOnMainThread(false);
195 startupTask->SetWaitOnMainThread(false);
196 return ERR_OK;
197 }
198
RunNativeStartupTask(const std::map<std::string,std::shared_ptr<StartupTask>> & nativeStartupTask)199 int32_t ExtNativeStartupManager::RunNativeStartupTask(
200 const std::map<std::string, std::shared_ptr<StartupTask>> &nativeStartupTask)
201 {
202 std::shared_ptr<StartupManager> startupManager = DelayedSingleton<StartupManager>::GetInstance();
203 if (startupManager == nullptr) {
204 TAG_LOGE(AAFwkTag::STARTUP, "failed to get startupManager");
205 return ERR_STARTUP_INTERNAL_ERROR;
206 }
207 std::shared_ptr<StartupTaskManager> startupTaskManager;
208 int32_t result = startupManager->BuildStartupTaskManager(nativeStartupTask, startupTaskManager);
209 if (result != ERR_OK || startupTaskManager == nullptr) {
210 TAG_LOGE(AAFwkTag::STARTUP, "build preload startup task manager failed, result: %{public}d", result);
211 return result;
212 }
213 result = startupTaskManager->Prepare();
214 if (result != ERR_OK) {
215 TAG_LOGE(AAFwkTag::STARTUP, "native startup task manager prepare failed, result: %{public}d", result);
216 return result;
217 }
218 TAG_LOGD(AAFwkTag::STARTUP, "native startup task manager run");
219 startupTaskManager->Run(nullptr);
220 return ERR_OK;
221 }
222
RegisterExtStartupTask(const std::shared_ptr<ExtNativeStartupTask> & extNativeStartupTask,const SchedulerPhase phase)223 int32_t ExtNativeStartupManager::RegisterExtStartupTask(
224 const std::shared_ptr<ExtNativeStartupTask> &extNativeStartupTask, const SchedulerPhase phase)
225 {
226 TAG_LOGD(AAFwkTag::STARTUP, "call");
227 if (extNativeStartupTask == nullptr) {
228 TAG_LOGE(AAFwkTag::STARTUP, "null extNativeStartupTask");
229 return ERR_STARTUP_INVALID_VALUE;
230 }
231 std::lock_guard guard(mutex_);
232 extNativeStartupTasks_[phase].push_back(extNativeStartupTask);
233 return ERR_OK;
234 }
235
RunPhaseTasks(const SchedulerPhase phase)236 int32_t ExtNativeStartupManager::RunPhaseTasks(const SchedulerPhase phase)
237 {
238 TAG_LOGD(AAFwkTag::STARTUP, "call");
239 std::lock_guard guard(mutex_);
240 auto findRes = extNativeStartupTasks_.find(phase);
241 if (findRes == extNativeStartupTasks_.end()) {
242 TAG_LOGD(AAFwkTag::STARTUP, "no phase task");
243 return ERR_OK;
244 }
245 if (findRes->second.empty()) {
246 TAG_LOGD(AAFwkTag::STARTUP, "no phase task");
247 return ERR_OK;
248 }
249 std::map<std::string, std::shared_ptr<StartupTask>> nativeStartupTask;
250 for (const auto &item : findRes->second) {
251 std::shared_ptr<StartupTask> startupTask;
252 int32_t res = BuildExtStartupTask(item, startupTask);
253 if (res != ERR_OK) {
254 TAG_LOGE(AAFwkTag::STARTUP, "failed to build task: %{public}d", res);
255 continue;
256 }
257 if (startupTask == nullptr) {
258 TAG_LOGE(AAFwkTag::STARTUP, "null startup task");
259 continue;
260 }
261 nativeStartupTask.emplace(startupTask->GetName(), startupTask);
262 }
263
264 if (nativeStartupTask.empty()) {
265 TAG_LOGD(AAFwkTag::STARTUP, "no valid task");
266 return ERR_STARTUP_INTERNAL_ERROR;
267 }
268 auto runTaskInitCallback = [nativeStartupTask]() {
269 RunNativeStartupTask(nativeStartupTask);
270 };
271 ffrt::submit(runTaskInitCallback);
272 return ERR_OK;
273 }
274 } // namespace AbilityRuntime
275 } // namespace OHOS
276