• 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 "plugin_mgr.h"
17 #include <cinttypes>
18 #include <algorithm>
19 #include <dlfcn.h>
20 #include <iostream>
21 #include <string>
22 #include "config_policy_utils.h"
23 #include "event_runner.h"
24 #include "hisysevent.h"
25 #include "res_sched_log.h"
26 #include "hitrace_meter.h"
27 
28 using namespace std;
29 
30 namespace OHOS {
31 namespace ResourceSchedule {
32 using namespace AppExecFwk;
33 using namespace HiviewDFX;
34 using OnPluginInitFunc = bool (*)(std::string);
35 
36 namespace {
37     const int32_t DISPATCH_WARNING_TIME = 10; // ms
38     const int32_t DISPATCH_TIME_OUT = 50; // ms
39     const std::string RUNNER_NAME = "rssDispatcher#";
40     const char* PLUGIN_SWITCH_FILE_NAME = "etc/ressched/res_sched_plugin_switch.xml";
41     const char* CONFIG_FILE_NAME = "etc/ressched/res_sched_config.xml";
42 }
43 
44 IMPLEMENT_SINGLE_INSTANCE(PluginMgr);
45 
~PluginMgr()46 PluginMgr::~PluginMgr()
47 {
48     OnDestroy();
49 }
50 
Init()51 void PluginMgr::Init()
52 {
53     if (pluginSwitch_) {
54         RESSCHED_LOGW("%{public}s, PluginMgr has Initialized!", __func__);
55         return;
56     }
57 
58     if (!pluginSwitch_) {
59         pluginSwitch_ = make_unique<PluginSwitch>();
60         std::string realPath = GetRealConfigPath(PLUGIN_SWITCH_FILE_NAME);
61         if (realPath.empty() || !pluginSwitch_->LoadFromConfigFile(realPath)) {
62             RESSCHED_LOGW("%{public}s, PluginMgr load switch config file failed!", __func__);
63         }
64     }
65 
66     if (!configReader_) {
67         configReader_ = make_unique<ConfigReader>();
68         std::string realPath = GetRealConfigPath(CONFIG_FILE_NAME);
69         if (realPath.empty() || !configReader_->LoadFromCustConfigFile(realPath)) {
70             RESSCHED_LOGW("%{public}s, PluginMgr load config file failed!", __func__);
71         }
72     }
73 
74     LoadPlugin();
75     RESSCHED_LOGI("PluginMgr::Init success!");
76 }
77 
LoadPlugin()78 void PluginMgr::LoadPlugin()
79 {
80     if (!pluginSwitch_) {
81         RESSCHED_LOGW("%{public}s, configReader null!", __func__);
82         return;
83     }
84 
85     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
86     for (const auto& info : pluginInfoList) {
87         if (!info.switchOn) {
88             continue;
89         }
90         shared_ptr<PluginLib> libInfoPtr = LoadOnePlugin(info);
91         if (libInfoPtr == nullptr) {
92             continue;
93         }
94         std::lock_guard<std::mutex> autoLock(pluginMutex_);
95         pluginLibMap_.emplace(info.libPath, *libInfoPtr);
96 
97         RESSCHED_LOGI("%{public}s, init %{public}s success!", __func__, info.libPath.c_str());
98     }
99 }
100 
LoadOnePlugin(const PluginInfo & info)101 shared_ptr<PluginLib> PluginMgr::LoadOnePlugin(const PluginInfo& info)
102 {
103     auto pluginHandle = dlopen(info.libPath.c_str(), RTLD_NOW);
104     if (!pluginHandle) {
105         RESSCHED_LOGE("%{public}s, not find plugin lib !", __func__);
106         return nullptr;
107     }
108 
109     auto onPluginInitFunc = reinterpret_cast<OnPluginInitFunc>(dlsym(pluginHandle, "OnPluginInit"));
110     if (!onPluginInitFunc) {
111         RESSCHED_LOGE("%{public}s, dlsym OnPluginInit failed!", __func__);
112         dlclose(pluginHandle);
113         return nullptr;
114     }
115 
116     auto onPluginDisableFunc = reinterpret_cast<OnPluginDisableFunc>(dlsym(pluginHandle, "OnPluginDisable"));
117     if (!onPluginDisableFunc) {
118         RESSCHED_LOGE("%{public}s, dlsym OnPluginDisable failed!", __func__);
119         dlclose(pluginHandle);
120         return nullptr;
121     }
122 
123     if (!onPluginInitFunc(info.libPath)) {
124         RESSCHED_LOGE("%{public}s, %{public}s init failed!", __func__, info.libPath.c_str());
125         dlclose(pluginHandle);
126         return nullptr;
127     }
128 
129     dispatcherHandlerMap_[info.libPath] =
130             std::make_shared<EventHandler>(EventRunner::Create(RUNNER_NAME + to_string(handlerNum_++)));
131 
132     // OnDispatchResource is not necessary for plugin
133     auto onDispatchResourceFunc = reinterpret_cast<OnDispatchResourceFunc>(dlsym(pluginHandle,
134         "OnDispatchResource"));
135 
136     // OnDispatchResource is not necessary for plugin
137     auto onDumpFunc = reinterpret_cast<OnDumpFunc>(dlsym(pluginHandle, "OnDump"));
138 
139     PluginLib libInfo;
140     libInfo.handle = nullptr;
141     libInfo.onPluginInitFunc_ = onPluginInitFunc;
142     libInfo.onDispatchResourceFunc_ = onDispatchResourceFunc;
143     libInfo.onDumpFunc_ = onDumpFunc;
144     libInfo.onPluginDisableFunc_ = onPluginDisableFunc;
145 
146     return make_shared<PluginLib>(libInfo);
147 }
148 
GetConfig(const std::string & pluginName,const std::string & configName)149 PluginConfig PluginMgr::GetConfig(const std::string& pluginName, const std::string& configName)
150 {
151     PluginConfig config;
152     if (!configReader_) {
153         return config;
154     }
155     return configReader_->GetConfig(pluginName, configName);
156 }
157 
Stop()158 void PluginMgr::Stop()
159 {
160     OnDestroy();
161 }
162 
RemoveDisablePluginHandler()163 void PluginMgr::RemoveDisablePluginHandler()
164 {
165     // clear already disable plugin handler
166     std::lock_guard<std::mutex> autoLock(disablePluginsMutex_);
167     dispatcherHandlerMutex_.lock();
168     for (auto plugin : disablePlugins_) {
169         RESSCHED_LOGI("PluginMgr::RemoveDisablePluginHandler remove %{plugin}s handler.", plugin.c_str());
170         auto iter = dispatcherHandlerMap_.find(plugin);
171         if (iter != dispatcherHandlerMap_.end()) {
172             auto runner = iter->second->GetEventRunner();
173             iter->second->RemoveAllEvents();
174             runner->Stop();
175             runner = nullptr;
176             iter->second = nullptr;
177             dispatcherHandlerMap_.erase(iter);
178         }
179     }
180     dispatcherHandlerMutex_.unlock();
181     disablePlugins_.clear();
182 }
183 
DispatchResource(const std::shared_ptr<ResData> & resData)184 void PluginMgr::DispatchResource(const std::shared_ptr<ResData>& resData)
185 {
186     RemoveDisablePluginHandler();
187     if (!resData) {
188         RESSCHED_LOGE("%{public}s, failed, null res data.", __func__);
189         return;
190     }
191     std::lock_guard<std::mutex> autoLock(resTypeMutex_);
192     auto iter = resTypeLibMap_.find(resData->resType);
193     if (iter == resTypeLibMap_.end()) {
194         RESSCHED_LOGD("%{public}s, PluginMgr resType no lib register!", __func__);
195         return;
196     }
197     std::string libNameAll = "[";
198     for (const auto& libName : iter->second) {
199         libNameAll.append(libName);
200         libNameAll.append(",");
201     }
202     libNameAll.append("]");
203     string trace_str(__func__);
204     string resTypeString =
205         ResType::resTypeToStr.count(resData->resType) ? ResType::resTypeToStr.at(resData->resType) : "UNKNOWN";
206     trace_str.append(" PluginMgr ,resType[").append(std::to_string(resData->resType)).append("]");
207     trace_str.append(",resTypeStr[").append(resTypeString).append("]");
208     trace_str.append(",value[").append(std::to_string(resData->value)).append("]");
209     trace_str.append(",pluginlist:").append(libNameAll);
210     StartTrace(HITRACE_TAG_OHOS, trace_str, -1);
211     RESSCHED_LOGD("%{public}s, PluginMgr, resType = %{public}d, "
212                   "value = %{public}lld, pluginlist is %{public}s.", __func__,
213                   resData->resType, (long long)resData->value, libNameAll.c_str());
214     FinishTrace(HITRACE_TAG_OHOS);
215     std::lock_guard<std::mutex> autoLock2(dispatcherHandlerMutex_);
216     for (const auto& libPath : iter->second) {
217         if (!dispatcherHandlerMap_[libPath]) {
218             RESSCHED_LOGE("%{public}s, failed, %{public}s dispatcher handler is stopped.", __func__,
219                 libPath.c_str());
220             continue;
221         }
222         dispatcherHandlerMap_[libPath]->PostTask(
223             [libPath, resData, this] { deliverResourceToPlugin(libPath, resData); });
224     }
225 }
226 
SubscribeResource(const std::string & pluginLib,uint32_t resType)227 void PluginMgr::SubscribeResource(const std::string& pluginLib, uint32_t resType)
228 {
229     if (pluginLib.size() == 0) {
230         RESSCHED_LOGE("%{public}s, PluginMgr failed, pluginLib is null.", __func__);
231         return;
232     }
233     std::lock_guard<std::mutex> autoLock(resTypeMutex_);
234     resTypeLibMap_[resType].emplace_back(pluginLib);
235 }
236 
UnSubscribeResource(const std::string & pluginLib,uint32_t resType)237 void PluginMgr::UnSubscribeResource(const std::string& pluginLib, uint32_t resType)
238 {
239     if (pluginLib.size() == 0) {
240         RESSCHED_LOGE("%{public}s, PluginMgr failed, pluginLib is null.", __func__);
241         return;
242     }
243     std::lock_guard<std::mutex> autoLock(resTypeMutex_);
244     auto iter = resTypeLibMap_.find(resType);
245     if (iter == resTypeLibMap_.end()) {
246         RESSCHED_LOGE("%{public}s, PluginMgr failed, res type has no plugin subscribe.", __func__);
247         return;
248     }
249 
250     iter->second.remove(pluginLib);
251     if (iter->second.empty()) {
252         resTypeLibMap_.erase(iter);
253     }
254 }
255 
DumpAllPlugin(std::string & result)256 void PluginMgr::DumpAllPlugin(std::string &result)
257 {
258     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
259     for (const auto& info : pluginInfoList) {
260         result.append(info.libPath + std::string(DUMP_ONE_STRING_SIZE - info.libPath.size(), ' '));
261         DumpPluginInfoAppend(result, info);
262     }
263 }
264 
DumpOnePlugin(std::string & result,std::string pluginName,std::vector<std::string> & args)265 void PluginMgr::DumpOnePlugin(std::string &result, std::string pluginName, std::vector<std::string>& args)
266 {
267     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
268     auto pos = std::find_if(pluginInfoList.begin(),
269         pluginInfoList.end(), [&pluginName](PluginInfo &info) { return pluginName == info.libPath; });
270     if (pos == pluginInfoList.end()) {
271         result.append(" Error params.\n");
272         return;
273     }
274     if (args.size() == 0) {
275         result.append(pluginName + std::string(DUMP_ONE_STRING_SIZE - pluginName.size(), ' '));
276         DumpPluginInfoAppend(result, *pos);
277     } else {
278         result.append("\n");
279         std::string errMsg = DumpInfoFromPlugin(result, pos->libPath, args);
280         if (errMsg != "") {
281             result.append(errMsg);
282         }
283     }
284 }
285 
DumpInfoFromPlugin(std::string & result,std::string libPath,std::vector<std::string> & args)286 std::string PluginMgr::DumpInfoFromPlugin(std::string& result, std::string libPath, std::vector<std::string>& args)
287 {
288     std::lock_guard<std::mutex> autoLock(pluginMutex_);
289     auto pluginLib = pluginLibMap_.find(libPath);
290     if (pluginLib == pluginLibMap_.end()) {
291         return "Error params.";
292     }
293 
294     if (pluginLib->second.onDumpFunc_) {
295         pluginLib->second.onDumpFunc_(args, result);
296         result.append("\n");
297     }
298     return "";
299 }
300 
DumpHelpFromPlugin(std::string & result)301 void PluginMgr::DumpHelpFromPlugin(std::string& result)
302 {
303     std::vector<std::string> args;
304     args.emplace_back("-h");
305     std::string pluginHelpMsg = "";
306     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
307     for (auto &pluginInfo : pluginInfoList) {
308         DumpInfoFromPlugin(pluginHelpMsg, pluginInfo.libPath, args);
309     }
310     result.append(pluginHelpMsg);
311 }
312 
DumpPluginInfoAppend(std::string & result,PluginInfo info)313 void PluginMgr::DumpPluginInfoAppend(std::string &result, PluginInfo info)
314 {
315     if (info.switchOn) {
316         result.append(" | switch on\t");
317     } else {
318         result.append(" | switch off\t");
319     }
320     std::lock_guard<std::mutex> autoLock(pluginMutex_);
321     if (pluginLibMap_.find(info.libPath) != pluginLibMap_.end()) {
322         result.append(" | running now\n");
323     } else {
324         result.append(" | disabled\n");
325     }
326 }
327 
GetRealConfigPath(const char * configName)328 std::string PluginMgr::GetRealConfigPath(const char* configName)
329 {
330     char buf[PATH_MAX + 1];
331     char* configFilePath = GetOneCfgFile(configName, buf, PATH_MAX + 1);
332     char tmpPath[PATH_MAX + 1] = {0};
333     if (!configFilePath || strlen(configFilePath) == 0 || strlen(configFilePath) > PATH_MAX ||
334         !realpath(configFilePath, tmpPath)) {
335         RESSCHED_LOGE("%{public}s load config file wrong !", __func__);
336         return "";
337     }
338     return std::string(tmpPath);
339 }
340 
ClearResource()341 void PluginMgr::ClearResource()
342 {
343     std::lock_guard<std::mutex> autoLock(resTypeMutex_);
344     resTypeLibMap_.clear();
345 }
346 
RepairPlugin(TimePoint endTime,const std::string & pluginLib,PluginLib libInfo)347 void PluginMgr::RepairPlugin(TimePoint endTime, const std::string& pluginLib, PluginLib libInfo)
348 {
349     int32_t crash_time = (int32_t)((endTime - pluginTimeoutTime_[pluginLib].front()) / std::chrono::milliseconds(1));
350     pluginTimeoutTime_[pluginLib].emplace_back(endTime);
351     RESSCHED_LOGW("%{public}s %{public}s crash %{public}d times in %{public}d ms!", __func__,
352         pluginLib.c_str(), (int32_t)pluginTimeoutTime_[pluginLib].size(), crash_time);
353     if ((int32_t)pluginTimeoutTime_[pluginLib].size() >= MAX_PLUGIN_TIMEOUT_TIMES) {
354         if (crash_time < DISABLE_PLUGIN_TIME) {
355             // disable plugin forever
356             RESSCHED_LOGE("%{public}s, %{public}s disable it forever", __func__, pluginLib.c_str());
357             if (libInfo.onPluginDisableFunc_) {
358                 libInfo.onPluginDisableFunc_();
359             }
360             HiSysEvent::Write("RSS", "PLUGIN_DISABLE",
361                 HiSysEvent::EventType::FAULT, "plugin_name", pluginLib);
362             pluginTimeoutTime_[pluginLib].clear();
363             pluginMutex_.lock();
364             auto itMap = pluginLibMap_.find(pluginLib);
365             pluginLibMap_.erase(itMap);
366             pluginMutex_.unlock();
367             std::lock_guard<std::mutex> autoLock(disablePluginsMutex_);
368             disablePlugins_.emplace_back(pluginLib);
369             return;
370         }
371 
372         auto iter = pluginTimeoutTime_[pluginLib].begin();
373         pluginTimeoutTime_[pluginLib].erase(iter);
374     }
375 
376     if (libInfo.onPluginDisableFunc_ && libInfo.onPluginInitFunc_) {
377         RESSCHED_LOGW("%{public}s, %{public}s disable and enable it", __func__, pluginLib.c_str());
378         libInfo.onPluginDisableFunc_();
379         libInfo.onPluginInitFunc_(pluginLib);
380     }
381 }
382 
deliverResourceToPlugin(const std::string & pluginLib,const std::shared_ptr<ResData> & resData)383 void PluginMgr::deliverResourceToPlugin(const std::string& pluginLib, const std::shared_ptr<ResData>& resData)
384 {
385     PluginLib libInfo;
386     {
387         std::lock_guard<std::mutex> autoLock(pluginMutex_);
388         auto itMap = pluginLibMap_.find(pluginLib);
389         if (itMap == pluginLibMap_.end()) {
390             RESSCHED_LOGE("%{public}s, no plugin %{public}s !", __func__, pluginLib.c_str());
391             return;
392         }
393         libInfo = itMap->second;
394     }
395 
396     OnDispatchResourceFunc pluginDispatchFunc = libInfo.onDispatchResourceFunc_;
397     if (!pluginDispatchFunc) {
398         RESSCHED_LOGE("%{public}s, no DispatchResourceFun !", __func__);
399         return;
400     }
401 
402     auto beginTime = Clock::now();
403     pluginDispatchFunc(resData);
404     auto endTime = Clock::now();
405     int32_t costTime = (endTime - beginTime) / std::chrono::milliseconds(1);
406     if (costTime > DISPATCH_TIME_OUT) {
407         // dispatch resource use too long time, unload it
408         RESSCHED_LOGE("%{public}s, ERROR :"
409                       "%{public}s plugin cost time(%{public}dms) over %{public}d ms! disable it.",
410                       __func__, pluginLib.c_str(), costTime, DISPATCH_TIME_OUT);
411         RepairPlugin(endTime, pluginLib, libInfo);
412     } else if (costTime > DISPATCH_WARNING_TIME) {
413         RESSCHED_LOGW("%{public}s, WARNING :"
414                       "%{public}s plugin cost time(%{public}dms) over %{public}d ms!",
415                       __func__, pluginLib.c_str(), costTime, DISPATCH_WARNING_TIME);
416     }
417 }
418 
UnLoadPlugin()419 void PluginMgr::UnLoadPlugin()
420 {
421     std::lock_guard<std::mutex> autoLock(pluginMutex_);
422     // unload all plugin
423     for (const auto& [libPath, libInfo] : pluginLibMap_) {
424         if (!libInfo.onPluginDisableFunc_) {
425             continue;
426         }
427         libInfo.onPluginDisableFunc_();
428     }
429     // close all plugin handle
430     pluginLibMap_.clear();
431 }
432 
OnDestroy()433 void PluginMgr::OnDestroy()
434 {
435     UnLoadPlugin();
436     configReader_ = nullptr;
437     ClearResource();
438     std::lock_guard<std::mutex> autoLock(dispatcherHandlerMutex_);
439     for (auto iter = dispatcherHandlerMap_.begin(); iter != dispatcherHandlerMap_.end();) {
440         if (iter->second != nullptr) {
441             iter->second->RemoveAllEvents();
442             iter->second = nullptr;
443         }
444         dispatcherHandlerMap_.erase(iter++);
445     }
446 }
447 
448 } // namespace ResourceSchedule
449 } // namespace OHOS
450