• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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