1 /*
2 * Copyright (c) 2022 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 <algorithm>
17 #include <dlfcn.h>
18 #include <iostream>
19 #include "datetime_ex.h"
20 #include "event_runner.h"
21 #include "res_sched_log.h"
22 #include "plugin_mgr.h"
23
24 using namespace std;
25
26 namespace OHOS {
27 namespace ResourceSchedule {
28 using namespace AppExecFwk;
29 using OnPluginInitFunc = bool (*)(std::string);
30 using Clock = std::chrono::high_resolution_clock;
31 using TimePoint = std::chrono::time_point<Clock>;
32
33 namespace {
34 const int DISPATCH_WARNING_TIME = 10; // ms
35 const int DISPATCH_TIME_OUT = 50; // ms
36 const std::string RUNNER_NAME = "rssDispatcher";
37 const std::string PLUGIN_SWITCH_FILE_NAME = "/system/etc/ressched/res_sched_plugin_switch.xml";
38 const std::string CONFIG_FILE_NAME = "/system/etc/ressched/res_sched_config.xml";
39 }
40
41 IMPLEMENT_SINGLE_INSTANCE(PluginMgr);
42
~PluginMgr()43 PluginMgr::~PluginMgr()
44 {
45 OnDestroy();
46 }
47
Init()48 void PluginMgr::Init()
49 {
50 RESSCHED_LOGI("PluginMgr::Init enter!");
51 if (pluginSwitch_) {
52 RESSCHED_LOGW("PluginMgr::Init has Initialized!");
53 return;
54 }
55
56 if (!pluginSwitch_) {
57 pluginSwitch_ = make_unique<PluginSwitch>();
58 char tmpPath[PATH_MAX + 1] = {0};
59 if (PLUGIN_SWITCH_FILE_NAME.size() == 0 || PLUGIN_SWITCH_FILE_NAME.size() > PATH_MAX ||
60 !realpath(PLUGIN_SWITCH_FILE_NAME.c_str(), tmpPath)) {
61 RESSCHED_LOGE("PluginMgr::load switch config file wrong !");
62 return ;
63 }
64 std::string realPath(tmpPath);
65 bool loadRet = pluginSwitch_->LoadFromConfigFile(realPath);
66 if (!loadRet) {
67 RESSCHED_LOGW("PluginMgr::Init load switch config file failed!");
68 }
69 }
70
71 if (!configReader_) {
72 configReader_ = make_unique<ConfigReader>();
73 char tmpPath[PATH_MAX + 1] = {0};
74 if (CONFIG_FILE_NAME.size() == 0 || CONFIG_FILE_NAME.size() > PATH_MAX ||
75 !realpath(CONFIG_FILE_NAME.c_str(), tmpPath)) {
76 RESSCHED_LOGE("PluginMgr::load config file wrong !");
77 return ;
78 }
79 std::string realPath(tmpPath);
80 bool loadRet = configReader_->LoadFromCustConfigFile(realPath);
81 if (!loadRet) {
82 RESSCHED_LOGW("PluginMgr::Init load config file failed!");
83 }
84 }
85
86 LoadPlugin();
87 if (!dispatcherHandler_) {
88 dispatcherHandler_ = std::make_shared<EventHandler>(EventRunner::Create(RUNNER_NAME));
89 }
90 RESSCHED_LOGI("PluginMgr::Init success!");
91 }
92
LoadPlugin()93 void PluginMgr::LoadPlugin()
94 {
95 if (!pluginSwitch_) {
96 RESSCHED_LOGW("PluginMgr::LoadPlugin configReader null!");
97 return;
98 }
99
100 std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
101 for (const auto& info : pluginInfoList) {
102 if (!info.switchOn) {
103 continue;
104 }
105
106 auto pluginHandle = dlopen(info.libPath.c_str(), RTLD_NOW);
107 if (!pluginHandle) {
108 RESSCHED_LOGE("PluginMgr::LoadPlugin not find plugin lib !");
109 continue;
110 }
111
112 auto onPluginInitFunc = reinterpret_cast<OnPluginInitFunc>(dlsym(pluginHandle, "OnPluginInit"));
113 if (!onPluginInitFunc) {
114 RESSCHED_LOGE("PluginMgr::LoadPlugin dlsym OnPluginInit failed!");
115 dlclose(pluginHandle);
116 continue;
117 }
118
119 auto onPluginDisableFunc = reinterpret_cast<OnPluginDisableFunc>(dlsym(pluginHandle, "OnPluginDisable"));
120 if (!onPluginDisableFunc) {
121 RESSCHED_LOGE("PluginMgr::LoadPlugin dlsym OnPluginDisable failed!");
122 dlclose(pluginHandle);
123 continue;
124 }
125 if (!onPluginInitFunc(info.libPath)) {
126 RESSCHED_LOGE("PluginMgr::LoadPlugin %{public}s init failed!", info.libPath.c_str());
127 dlclose(pluginHandle);
128 continue;
129 }
130
131 // OnDispatchResource is not necessary for plugin
132 auto onDispatchResourceFunc = reinterpret_cast<OnDispatchResourceFunc>(dlsym(pluginHandle,
133 "OnDispatchResource"));
134
135 // shared_ptr save handle pointer and ensure handle close correctly
136 shared_ptr<void> sharedPluginHandle(pluginHandle, CloseHandle);
137
138 PluginLib libInfo;
139 libInfo.handle = sharedPluginHandle;
140 libInfo.onDispatchResourceFunc_ = onDispatchResourceFunc;
141 libInfo.onPluginDisableFunc_ = onPluginDisableFunc;
142 {
143 std::lock_guard<std::mutex> autoLock(pluginMutex_);
144 pluginLibMap_.emplace(info.libPath, libInfo);
145 }
146 RESSCHED_LOGE("PluginMgr::LoadPlugin init %{public}s success!", info.libPath.c_str());
147 }
148 }
149
GetConfig(const std::string & pluginName,const std::string & configName)150 PluginConfig PluginMgr::GetConfig(const std::string& pluginName, const std::string& configName)
151 {
152 PluginConfig config;
153 if (!configReader_) {
154 return config;
155 }
156 return configReader_->GetConfig(pluginName, configName);
157 }
158
Stop()159 void PluginMgr::Stop()
160 {
161 OnDestroy();
162 }
163
DispatchResource(const std::shared_ptr<ResData> & resData)164 void PluginMgr::DispatchResource(const std::shared_ptr<ResData>& resData)
165 {
166 if (!resData) {
167 RESSCHED_LOGE("PluginMgr::DispatchResource failed, null res data.");
168 return;
169 }
170
171 if (!dispatcherHandler_) {
172 RESSCHED_LOGE("PluginMgr::DispatchResource failed, dispatcher is stopped.");
173 return;
174 }
175
176 std::lock_guard<std::mutex> autoLock(resTypeMutex_);
177 auto iter = resTypeLibMap_.find(resData->resType);
178 if (iter == resTypeLibMap_.end()) {
179 RESSCHED_LOGW("PluginMgr::DispatchResource resType no lib register!");
180 return;
181 }
182 std::string libNameAll = "[";
183 for (const auto& libName : iter->second) {
184 libNameAll.append(libName);
185 libNameAll.append(",");
186 }
187 libNameAll.append("]");
188 RESSCHED_LOGI("PluginMgr::DispatchResource resType = %{public}d, value = %{public}lld pluginlist is %{public}s.",
189 resData->resType, resData->value, libNameAll.c_str());
190 {
191 std::lock_guard<std::mutex> autoLock(dispatcherHandlerMutex_);
192 for (const auto& libPath : iter->second) {
193 dispatcherHandler_->PostTask(
194 [libPath, resData, this] { deliverResourceToPlugin(libPath, resData); });
195 }
196 }
197 }
198
SubscribeResource(const std::string & pluginLib,uint32_t resType)199 void PluginMgr::SubscribeResource(const std::string& pluginLib, uint32_t resType)
200 {
201 if (pluginLib.size() == 0) {
202 RESSCHED_LOGE("PluginMgr::SubscribeResource failed, pluginLib is null.");
203 return;
204 }
205 std::lock_guard<std::mutex> autoLock(resTypeMutex_);
206 resTypeLibMap_[resType].emplace_back(pluginLib);
207 }
208
UnSubscribeResource(const std::string & pluginLib,uint32_t resType)209 void PluginMgr::UnSubscribeResource(const std::string& pluginLib, uint32_t resType)
210 {
211 if (pluginLib.size() == 0) {
212 RESSCHED_LOGE("PluginMgr::UnSubscribeResource failed, pluginLib is null.");
213 return;
214 }
215 std::lock_guard<std::mutex> autoLock(resTypeMutex_);
216 auto iter = resTypeLibMap_.find(resType);
217 if (iter == resTypeLibMap_.end()) {
218 RESSCHED_LOGE("PluginMgr::UnSubscribeResource failed, res type has no plugin subscribe.");
219 return;
220 }
221
222 iter->second.remove(pluginLib);
223 if (iter->second.empty()) {
224 resTypeLibMap_.erase(iter);
225 }
226 }
227
ClearResource()228 void PluginMgr::ClearResource()
229 {
230 std::lock_guard<std::mutex> autoLock(resTypeMutex_);
231 resTypeLibMap_.clear();
232 }
233
deliverResourceToPlugin(const std::string & pluginLib,const std::shared_ptr<ResData> & resData)234 void PluginMgr::deliverResourceToPlugin(const std::string& pluginLib, const std::shared_ptr<ResData>& resData)
235 {
236 std::lock_guard<std::mutex> autoLock(pluginMutex_);
237 auto itMap = pluginLibMap_.find(pluginLib);
238 if (itMap == pluginLibMap_.end()) {
239 RESSCHED_LOGE("PluginMgr::deliverResourceToPlugin no plugin %{public}s !", pluginLib.c_str());
240 return;
241 }
242 OnDispatchResourceFunc fun = itMap->second.onDispatchResourceFunc_;
243 if (!fun) {
244 RESSCHED_LOGE("PluginMgr::deliverResourceToPlugin no DispatchResourceFun !");
245 return;
246 }
247
248 auto beginTime = Clock::now();
249 fun(resData);
250 auto endTime = Clock::now();
251 int costTime = (endTime - beginTime) / std::chrono::milliseconds(1);
252 if (costTime > DISPATCH_TIME_OUT) {
253 // dispatch resource use too long time, unload it
254 RESSCHED_LOGE("PluginMgr::deliverResourceToPlugin ERROR :"
255 "%{public}s plugin cost time(%{public}dms) over 50 ms! disable it.",
256 pluginLib.c_str(), costTime);
257 if (itMap->second.onPluginDisableFunc_) {
258 itMap->second.onPluginDisableFunc_();
259 }
260 pluginLibMap_.erase(itMap);
261 } else if (costTime > DISPATCH_WARNING_TIME) {
262 RESSCHED_LOGW("PluginMgr::deliverResourceToPlugin WAINNING :"
263 "%{public}s plugin cost time(%{public}dms) over 10 ms!",
264 pluginLib.c_str(), costTime);
265 }
266 }
267
UnLoadPlugin()268 void PluginMgr::UnLoadPlugin()
269 {
270 std::lock_guard<std::mutex> autoLock(pluginMutex_);
271 // unload all plugin
272 for (const auto& [libPath, libInfo] : pluginLibMap_) {
273 if (!libInfo.onPluginDisableFunc_) {
274 continue;
275 }
276 libInfo.onPluginDisableFunc_();
277 }
278 // close all plugin handle
279 pluginLibMap_.clear();
280 }
281
OnDestroy()282 void PluginMgr::OnDestroy()
283 {
284 UnLoadPlugin();
285 configReader_ = nullptr;
286 ClearResource();
287
288 if (dispatcherHandler_) {
289 std::lock_guard<std::mutex> autoLock(dispatcherHandlerMutex_);
290 dispatcherHandler_->RemoveAllEvents();
291 dispatcherHandler_ = nullptr;
292 }
293 }
294
CloseHandle(const DlHandle & handle)295 void PluginMgr::CloseHandle(const DlHandle& handle)
296 {
297 if (!handle) {
298 RESSCHED_LOGW("PluginMgr::CloseHandle nullptr handle!");
299 return;
300 }
301
302 int ret = dlclose(handle);
303 if (ret) {
304 RESSCHED_LOGW("PluginMgr::CloseHandle handle close failed!");
305 }
306 }
307 } // namespace ResourceSchedule
308 } // namespace OHOS
309