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