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