• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "plugin_mgr.h"
17 #include <cinttypes>
18 #include <algorithm>
19 #include <cstdint>
20 #include <dlfcn.h>
21 #include <iostream>
22 #include <string>
23 #include <string_ex.h>
24 #include <fstream>
25 #include "config_policy_utils.h"
26 #include "file_ex.h"
27 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
28 #include "ffrt_inner.h"
29 #else
30 #include "event_runner.h"
31 #endif
32 #include "hisysevent.h"
33 #include "refbase.h"
34 #include "res_sched_log.h"
35 #include "hitrace_meter.h"
36 #include "batch_log_printer.h"
37 
38 using namespace std;
39 
40 namespace OHOS {
41 namespace ResourceSchedule {
42 using namespace AppExecFwk;
43 using namespace HiviewDFX;
44 
45 namespace {
46     static const int32_t DISPATCH_WARNING_TIME = 10; // ms
47     static const int32_t PLUGIN_SWITCH_FILE_IDX = 0;
48     static const int32_t CONFIG_FILE_IDX = 1;
49     static const int32_t SIMPLIFY_LIB_INDEX = 3;
50     static const int32_t SIMPLIFY_LIB_LENGTH = 5;
51     static const int32_t MAX_FILE_LENGTH = 32 * 1024 * 1024;
52     static const int32_t PLUGIN_REQUEST_ERROR = -1;
53     static const char* RUNNER_NAME = "rssDispatcher";
54     static const char* PLUGIN_SWITCH_FILE_NAME = "etc/ressched/res_sched_plugin_switch.xml";
55     static const char* CONFIG_FILE_NAME = "etc/ressched/res_sched_config.xml";
56     static const char* EXT_CONFIG_LIB = "libsuspend_manager_service.z.so";
57 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_EXT_RES_ENABLE
58     static const int32_t DEFAULT_VALUE = -1;
59     static const char* EXT_RES_KEY = "extType";
60 #endif
61 }
62 
63 IMPLEMENT_SINGLE_INSTANCE(PluginMgr);
64 
~PluginMgr()65 PluginMgr::~PluginMgr()
66 {
67     OnDestroy();
68 }
69 
Init(bool isRssExe)70 void PluginMgr::Init(bool isRssExe)
71 {
72     if (pluginSwitch_) {
73         RESSCHED_LOGW("%{public}s, PluginMgr has Initialized!", __func__);
74         return;
75     }
76 
77     if (!pluginSwitch_) {
78         pluginSwitch_ = make_unique<PluginSwitch>();
79     }
80     if (!configReader_) {
81         configReader_ = make_unique<ConfigReader>();
82     }
83 
84     if (!isRssExe) {
85         LoadGetExtConfigFunc();
86     }
87     RESSCHED_LOGI("PluginMgr::Init success!");
88 }
89 
GetConfigReaderStr()90 std::vector<std::string> PluginMgr::GetConfigReaderStr()
91 {
92     std::vector<std::string> configStrs;
93     GetConfigContent(CONFIG_FILE_IDX, CONFIG_FILE_NAME, configStrs);
94     return configStrs;
95 }
96 
GetPluginSwitchStr()97 std::vector<std::string> PluginMgr::GetPluginSwitchStr()
98 {
99     std::vector<std::string> switchStrs;
100     GetConfigContent(PLUGIN_SWITCH_FILE_IDX, PLUGIN_SWITCH_FILE_NAME, switchStrs);
101     return switchStrs;
102 }
103 
ParseConfigReader(const std::vector<std::string> & configStrs)104 void PluginMgr::ParseConfigReader(const std::vector<std::string>& configStrs)
105 {
106     if (!configReader_) {
107         RESSCHED_LOGW("%{public}s, configReader null!", __func__);
108         return;
109     }
110 
111     int32_t configStrsSize = static_cast<int32_t>(configStrs.size());
112     RESSCHED_LOGI("plugin configStrs size %{public}d", configStrsSize);
113     for (int index = 0; index < configStrsSize; index++) {
114         if (configStrs[index].empty()) {
115             continue;
116         }
117         if (!configReader_->LoadFromConfigContent(configStrs[index])) {
118             RESSCHED_LOGW("%{public}s, PluginMgr load config file index:%{public}d failed!", __func__, index);
119             HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "INIT_FAULT",
120                 HiviewDFX::HiSysEvent::EventType::FAULT,
121                 "COMPONENT_NAME", "MAIN", "ERR_TYPE", "configure error",
122                 "ERR_MSG", "PluginMgr load parameter config file failed");
123             continue;
124         }
125         RESSCHED_LOGI("PluginMgr load config file index:%{public}d success!", index);
126     }
127 }
128 
ParsePluginSwitch(const std::vector<std::string> & switchStrs,bool isRssExe)129 void PluginMgr::ParsePluginSwitch(const std::vector<std::string>& switchStrs, bool isRssExe)
130 {
131     if (!pluginSwitch_) {
132         RESSCHED_LOGW("%{public}s, pluginSwitch null!", __func__);
133         return;
134     }
135 
136     int32_t switchStrsSize = static_cast<int32_t>(switchStrs.size());
137     RESSCHED_LOGI("plugin switchStrs size %{public}d", switchStrsSize);
138     for (int32_t index = 0; index < switchStrsSize; index++) {
139         if (switchStrs[index].empty()) {
140             continue;
141         }
142         if (!pluginSwitch_->LoadFromConfigContent(switchStrs[index], isRssExe)) {
143             RESSCHED_LOGW("%{public}s, PluginMgr load switch config file index:%{public}d failed!", __func__, index);
144             HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "INIT_FAULT",
145                 HiviewDFX::HiSysEvent::EventType::FAULT,
146                 "COMPONENT_NAME", "MAIN", "ERR_TYPE", "configure error",
147                 "ERR_MSG", "PluginMgr load switch config file failed!");
148             continue;
149         }
150         RESSCHED_LOGI("PluginMgr load switch config file index:%{public}d success!", index);
151     }
152     LoadPlugin();
153 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
154     std::lock_guard<ffrt::mutex> autoLock(dispatcherHandlerMutex_);
155 #else
156     std::lock_guard<std::mutex> autoLock(dispatcherHandlerMutex_);
157 #endif
158 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
159     dispatchers_.clear();
160     for (const auto& [libPath, libInfo] : pluginLibMap_) {
161         auto callback = [pluginName = libPath, time = pluginBlockTime]() {
162             PluginMgr::GetInstance().HandlePluginTimeout(pluginName);
163             ffrt::submit([pluginName]() {
164                 PluginMgr::GetInstance().EnablePluginIfResume(pluginName);
165                 }, {}, {}, ffrt::task_attr().delay(time));
166         };
167         dispatchers_.emplace(libPath, std::make_shared<ffrt::queue>(libPath.c_str(),
168             ffrt::queue_attr().qos(ffrt::qos_user_interactive)));
169     }
170 #else
171     if (!dispatcher_) {
172         dispatcher_ = std::make_shared<EventHandler>(EventRunner::Create(RUNNER_NAME));
173     }
174     if (!dispatcher_) {
175         RESSCHED_LOGI("create dispatcher failed");
176     }
177 #endif
178     isInit = true;
179     RESSCHED_LOGI("PluginMgr load plugin success!");
180 }
181 
LoadGetExtConfigFunc()182 void PluginMgr::LoadGetExtConfigFunc()
183 {
184     auto handle = dlopen(EXT_CONFIG_LIB, RTLD_NOW);
185     if (!handle) {
186         RESSCHED_LOGE("not find lib,errno: %{public}d", errno);
187         return;
188     }
189     getExtMultiConfigFunc_ = reinterpret_cast<GetExtMultiConfigFunc>(dlsym(handle, "GetExtMultiConfig"));
190     if (!getExtMultiConfigFunc_) {
191         RESSCHED_LOGE("dlsym getExtConfig func failed!");
192         dlclose(handle);
193     }
194 }
195 
GetConfigContent(int32_t configIdx,const std::string & configPath,std::vector<std::string> & contents)196 void PluginMgr::GetConfigContent(int32_t configIdx, const std::string& configPath, std::vector<std::string>& contents)
197 {
198     if (configIdx != -1 && getExtMultiConfigFunc_) {
199         getExtMultiConfigFunc_(configIdx, contents);
200         return;
201     }
202     auto configFilePaths = GetAllRealConfigPath(configPath);
203     if (configFilePaths.size() <= 0) {
204         return;
205     }
206     std::ifstream ifs;
207     for (auto configFilePath : configFilePaths) {
208         if (configFilePath.empty()) {
209             continue;
210         }
211         std::string content;
212         LoadStringFromFile(configFilePath, content);
213         contents.emplace_back(content);
214     }
215 }
216 
GetAllRealConfigPath(const std::string & configName)217 std::vector<std::string> PluginMgr::GetAllRealConfigPath(const std::string& configName)
218 {
219     std::vector<std::string> configFilePaths;
220     auto cfgDirList = GetCfgDirList();
221     if (cfgDirList == nullptr) {
222         return configFilePaths;
223     }
224     std::string baseRealPath;
225     for (const auto& cfgDir : cfgDirList->paths) {
226         if (cfgDir == nullptr) {
227             continue;
228         }
229         if (!CheckRealPath(std::string(cfgDir) + "/" + configName, baseRealPath)) {
230             continue;
231         }
232         configFilePaths.emplace_back(baseRealPath);
233     }
234     FreeCfgDirList(cfgDirList);
235     return configFilePaths;
236 }
237 
CheckRealPath(const std::string & partialPath,std::string & fullPath)238 bool PluginMgr::CheckRealPath(const std::string& partialPath, std::string& fullPath)
239 {
240     char tmpPath[PATH_MAX] = {0};
241     if (partialPath.size() > PATH_MAX || !realpath(partialPath.c_str(), tmpPath)) {
242         return false;
243     }
244     fullPath = tmpPath;
245     return true;
246 }
247 
LoadPlugin()248 void PluginMgr::LoadPlugin()
249 {
250     if (!pluginSwitch_) {
251         RESSCHED_LOGW("%{public}s, pluginSwitch null!", __func__);
252         return;
253     }
254 
255     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
256     for (const auto& info : pluginInfoList) {
257         if (!info.switchOn) {
258             continue;
259         }
260         if (pluginLibMap_.find(info.libPath) != pluginLibMap_.end()) {
261             continue;
262         }
263         shared_ptr<PluginLib> libInfoPtr = LoadOnePlugin(info);
264         if (libInfoPtr == nullptr) {
265             continue;
266         }
267         std::lock_guard<std::mutex> autoLock(pluginMutex_);
268         pluginLibMap_.emplace(info.libPath, *libInfoPtr);
269 
270         RESSCHED_LOGD("%{public}s, init %{private}s success!", __func__, info.libPath.c_str());
271     }
272 }
273 
LoadOnePlugin(const PluginInfo & info)274 shared_ptr<PluginLib> PluginMgr::LoadOnePlugin(const PluginInfo& info)
275 {
276     auto pluginHandle = dlopen(info.libPath.c_str(), RTLD_NOW);
277     if (!pluginHandle) {
278         RESSCHED_LOGE("%{public}s, not find plugin lib !", __func__);
279         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "INIT_FAULT", HiviewDFX::HiSysEvent::EventType::FAULT,
280                         "COMPONENT_NAME", "MAIN", "ERR_TYPE", "plugin failure",
281                         "ERR_MSG", "PluginMgr dlopen " + info.libPath + " failed!");
282         return nullptr;
283     }
284 
285     auto onPluginInitFunc = reinterpret_cast<OnPluginInitFunc>(dlsym(pluginHandle, "OnPluginInit"));
286     if (!onPluginInitFunc) {
287         RESSCHED_LOGE("%{public}s, dlsym OnPluginInit failed!", __func__);
288         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "INIT_FAULT", HiviewDFX::HiSysEvent::EventType::FAULT,
289                         "COMPONENT_NAME", "MAIN", "ERR_TYPE", "plugin failure",
290                         "ERR_MSG", "PluginMgr dlsym 'OnPluginInit' in " + info.libPath + "failed!");
291         dlclose(pluginHandle);
292         return nullptr;
293     }
294 
295     auto onPluginDisableFunc = reinterpret_cast<OnPluginDisableFunc>(dlsym(pluginHandle, "OnPluginDisable"));
296     if (!onPluginDisableFunc) {
297         RESSCHED_LOGE("%{public}s, dlsym OnPluginDisable failed!", __func__);
298         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "INIT_FAULT", HiviewDFX::HiSysEvent::EventType::FAULT,
299                         "COMPONENT_NAME", "MAIN", "ERR_TYPE", "plugin failure",
300                         "ERR_MSG", "PluginMgr dlsym 'OnPluginDisable' in " + info.libPath + "failed!");
301         dlclose(pluginHandle);
302         return nullptr;
303     }
304 
305     if (!onPluginInitFunc(const_cast<std::string&>(info.libPath))) {
306         RESSCHED_LOGE("%{public}s, %{private}s init failed!", __func__, info.libPath.c_str());
307         HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "INIT_FAULT", HiviewDFX::HiSysEvent::EventType::FAULT,
308                         "COMPONENT_NAME", "MAIN", "ERR_TYPE", "plugin failure",
309                         "ERR_MSG", "Plugin " + info.libPath + " init failed!");
310         dlclose(pluginHandle);
311         return nullptr;
312     }
313 
314     // OnDispatchResource is not necessary for plugin
315     auto onDispatchResourceFunc = reinterpret_cast<OnDispatchResourceFunc>(dlsym(pluginHandle,
316         "OnDispatchResource"));
317 
318     // OnDeliverResource is not necessary for plugin
319     auto onDeliverResourceFunc = reinterpret_cast<OnDeliverResourceFunc>(dlsym(pluginHandle,
320         "OnDeliverResource"));
321 
322     // OnDispatchResource is not necessary for plugin
323     auto onDumpFunc = reinterpret_cast<OnDumpFunc>(dlsym(pluginHandle, "OnDump"));
324 
325     PluginLib libInfo;
326     libInfo.handle = std::shared_ptr<void>(pluginHandle, dlclose);
327     libInfo.onPluginInitFunc_ = onPluginInitFunc;
328     libInfo.onDispatchResourceFunc_ = onDispatchResourceFunc;
329     libInfo.onDeliverResourceFunc_ = onDeliverResourceFunc;
330     libInfo.onDumpFunc_ = onDumpFunc;
331     libInfo.onPluginDisableFunc_ = onPluginDisableFunc;
332 
333     return make_shared<PluginLib>(libInfo);
334 }
335 
GetConfig(const std::string & pluginName,const std::string & configName)336 PluginConfig PluginMgr::GetConfig(const std::string& pluginName, const std::string& configName)
337 {
338     PluginConfig config;
339     if (!configReader_) {
340         return config;
341     }
342     return configReader_->GetConfig(pluginName, configName);
343 }
344 
RemoveConfig(const std::string & pluginName,const std::string & configName)345 void PluginMgr::RemoveConfig(const std::string& pluginName, const std::string& configName)
346 {
347     PluginConfig config;
348     if (!configReader_) {
349         return;
350     }
351     configReader_->RemoveConfig(pluginName, configName);
352 }
353 
Stop()354 void PluginMgr::Stop()
355 {
356     OnDestroy();
357 }
358 
359 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_EXT_RES_ENABLE
GetExtTypeByResPayload(const std::shared_ptr<ResData> & resData)360 int32_t PluginMgr::GetExtTypeByResPayload(const std::shared_ptr<ResData>& resData)
361 {
362     if (!resData || resData->resType != ResType::RES_TYPE_KEY_PERF_SCENE) {
363         return DEFAULT_VALUE;
364     }
365     auto payload = resData->payload;
366     if (!payload.contains(EXT_RES_KEY) || !payload[EXT_RES_KEY].is_string()) {
367         return DEFAULT_VALUE;
368     }
369     int type = DEFAULT_VALUE;
370     if (StrToInt(payload[EXT_RES_KEY], type)) {
371         return type;
372     } else {
373         return DEFAULT_VALUE;
374     }
375 }
376 #endif
377 
GetPluginListByResType(uint32_t resType,std::list<std::string> & pluginList)378 bool PluginMgr::GetPluginListByResType(uint32_t resType, std::list<std::string>& pluginList)
379 {
380     std::lock_guard<std::mutex> autoLock(resTypeMutex_);
381     auto iter = resTypeLibMap_.find(resType);
382     if (iter == resTypeLibMap_.end()) {
383         RESSCHED_LOGD("%{public}s, PluginMgr resType no lib register!", __func__);
384         return false;
385     }
386     pluginList = iter->second;
387     return true;
388 }
389 
BuildSimplifyLibAll(const std::list<std::string> & pluginList,std::string & simplifyLibAll)390 inline void BuildSimplifyLibAll(const std::list<std::string>& pluginList, std::string& simplifyLibAll)
391 {
392     for (const auto& libName : pluginList) {
393         if (simplifyLibAll.length() != 0) {
394             simplifyLibAll.append(":");
395         }
396         simplifyLibAll.append(libName.substr(SIMPLIFY_LIB_INDEX, SIMPLIFY_LIB_LENGTH));
397     }
398 }
399 
GetPluginLib(const std::string & libPath)400 std::shared_ptr<PluginLib> PluginMgr::GetPluginLib(const std::string& libPath)
401 {
402     std::lock_guard<std::mutex> autoLock(libPathMutex_);
403     auto iter = pluginLibMap_.find(libPath);
404     if (iter == pluginLibMap_.end()) {
405         RESSCHED_LOGE("%{public}s, PluginMgr libPath no lib register!", __func__);
406         return nullptr;
407     }
408     return make_shared<PluginLib>(iter->second);
409 }
410 
BuildDispatchTrace(const std::shared_ptr<ResData> & resData,std::string & libNameAll,const std::string & funcName,std::list<std::string> & pluginList)411 std::string PluginMgr::BuildDispatchTrace(const std::shared_ptr<ResData>& resData, std::string& libNameAll,
412     const std::string& funcName, std::list<std::string>& pluginList)
413 {
414     libNameAll.append("[");
415     for (const auto& libName : pluginList) {
416 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
417         if (disablePlugins_.find(libName) != disablePlugins_.end()) {
418             continue;
419         }
420 #endif
421         libNameAll.append(libName);
422         libNameAll.append(",");
423     }
424     libNameAll.append("]");
425     string trace_str(funcName);
426     string resTypeString = GetStrFromResTypeStrMap(resData->resType);
427     trace_str.append(" PluginMgr ,resType[").append(std::to_string(resData->resType)).append("]");
428     trace_str.append(",resTypeStr[").append(resTypeString).append("]");
429     trace_str.append(",value[").append(std::to_string(resData->value)).append("]");
430     trace_str.append(",pluginlist:").append(libNameAll);
431     return trace_str;
432 }
433 
DispatchResource(const std::shared_ptr<ResData> & resData)434 void PluginMgr::DispatchResource(const std::shared_ptr<ResData>& resData)
435 {
436     if (!isInit.load()) {
437         RESSCHED_LOGE("%{public}s, not init.", __func__);
438         return;
439     }
440     if (!resData) {
441         RESSCHED_LOGE("%{public}s, failed, null res data.", __func__);
442         return;
443     }
444     std::list<std::string> pluginList;
445 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_EXT_RES_ENABLE
446     int32_t extType = GetExtTypeByResPayload(resData);
447     if (extType != DEFAULT_VALUE) {
448         resData->resType = (uint32_t)extType;
449     }
450 #endif
451     if (!GetPluginListByResType(resData->resType, pluginList)) {
452         return;
453     }
454     std::string libNameAll = "";
455     string trace_str = BuildDispatchTrace(resData, libNameAll, __func__, pluginList);
456     StartTrace(HITRACE_TAG_APP, trace_str, -1);
457     RESSCHED_LOGD("%{public}s, PluginMgr, resType = %{public}d, value = %{public}lld, pluginlist is %{public}s.",
458         __func__, resData->resType, (long long)resData->value, libNameAll.c_str());
459     FinishTrace(HITRACE_TAG_APP);
460     std::string simplifyLibAll = "";
461     BuildSimplifyLibAll(pluginList, simplifyLibAll);
462     BatchLogPrinter::GetInstance().SubmitLog(std::to_string(resData->resType).
463         append(",").append(std::to_string(resData->value)).append(",").append(simplifyLibAll));
464 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
465     DispatchResourceToPluginAsync(pluginList, resData);
466 #else
467     std::lock_guard<std::mutex> autoLock(dispatcherHandlerMutex_);
468     if (dispatcher_) {
469         dispatcher_->PostTask(
470             [pluginList, resData, this] {
471                 DispatchResourceToPluginSync(pluginList, resData);
472             });
473     }
474 #endif
475 }
476 
DeliverResource(const std::shared_ptr<ResData> & resData)477 int32_t PluginMgr::DeliverResource(const std::shared_ptr<ResData>& resData)
478 {
479     if (!isInit.load()) {
480         RESSCHED_LOGE("%{public}s, not init.", __func__);
481         return PLUGIN_REQUEST_ERROR;
482     }
483 
484     if (!resData) {
485         RESSCHED_LOGE("%{public}s, failed, null res data.", __func__);
486         return PLUGIN_REQUEST_ERROR;
487     }
488 
489     std::string pluginLib;
490     {
491         std::lock_guard<std::mutex> autoLock(resTypeSyncMutex_);
492         auto iter = resTypeLibSyncMap_.find(resData->resType);
493         if (iter == resTypeLibSyncMap_.end()) {
494             RESSCHED_LOGE("%{public}s, PluginMgr resType %{public}d no lib register!", __func__, resData->resType);
495             return PLUGIN_REQUEST_ERROR;
496         }
497         pluginLib = iter->second;
498     }
499 
500     PluginLib libInfo;
501     {
502         std::lock_guard<std::mutex> autoLock(pluginMutex_);
503         auto itMap = pluginLibMap_.find(pluginLib);
504         if (itMap == pluginLibMap_.end()) {
505             RESSCHED_LOGE("%{public}s, no plugin %{public}s!", __func__, pluginLib.c_str());
506             return PLUGIN_REQUEST_ERROR;
507         }
508         libInfo = itMap->second;
509     }
510 
511     OnDeliverResourceFunc pluginDeliverFunc = libInfo.onDeliverResourceFunc_;
512     if (!pluginDeliverFunc) {
513         RESSCHED_LOGE("%{public}s, %{public}s no DeliverResourceFunc!", __func__, pluginLib.c_str());
514         return PLUGIN_REQUEST_ERROR;
515     }
516     RESSCHED_LOGD("%{public}s, PluginMgr, resType = %{public}d, value = %{public}lld, plugin is %{public}s.",
517         __func__, resData->resType, (long long)resData->value, pluginLib.c_str());
518 
519     int32_t ret;
520     {
521         std::string libName = "";
522         std::list<std::string> pluginList = { pluginLib };
523         std::string traceStr = BuildDispatchTrace(resData, libName, __func__, pluginList);
524         HitraceScoped hitrace(HITRACE_TAG_OHOS, traceStr);
525         InnerTimeUtil timeUtil(__func__, pluginLib);
526         ret = pluginDeliverFunc(resData);
527     }
528     return ret;
529 }
530 
SubscribeResource(const std::string & pluginLib,uint32_t resType)531 void PluginMgr::SubscribeResource(const std::string& pluginLib, uint32_t resType)
532 {
533     if (pluginLib.size() == 0) {
534         RESSCHED_LOGE("%{public}s, PluginMgr failed, pluginLib is null.", __func__);
535         return;
536     }
537     std::lock_guard<std::mutex> autoLock(resTypeMutex_);
538     resTypeLibMap_[resType].emplace_back(pluginLib);
539 }
540 
UnSubscribeResource(const std::string & pluginLib,uint32_t resType)541 void PluginMgr::UnSubscribeResource(const std::string& pluginLib, uint32_t resType)
542 {
543     if (pluginLib.size() == 0) {
544         RESSCHED_LOGE("%{public}s, PluginMgr failed, pluginLib is null.", __func__);
545         return;
546     }
547     std::lock_guard<std::mutex> autoLock(resTypeMutex_);
548     auto iter = resTypeLibMap_.find(resType);
549     if (iter == resTypeLibMap_.end()) {
550         RESSCHED_LOGE("%{public}s, PluginMgr failed, res type has no plugin subscribe.", __func__);
551         return;
552     }
553 
554     iter->second.remove(pluginLib);
555     if (iter->second.empty()) {
556         resTypeLibMap_.erase(iter);
557     }
558 }
559 
SubscribeSyncResource(const std::string & pluginLib,uint32_t resType)560 void PluginMgr::SubscribeSyncResource(const std::string& pluginLib, uint32_t resType)
561 {
562     if (pluginLib.empty()) {
563         RESSCHED_LOGE("%{public}s, PluginMgr failed, pluginLib is null.", __func__);
564         return;
565     }
566     std::lock_guard<std::mutex> autoLock(resTypeSyncMutex_);
567     auto iter = resTypeLibSyncMap_.find(resType);
568     if (iter != resTypeLibSyncMap_.end()) {
569         RESSCHED_LOGW("%{public}s, resType[%{public}d] subcribed by [%{public}s], replace by [%{public}s].",
570             __func__, resType, iter->second.c_str(), pluginLib.c_str());
571     }
572     resTypeLibSyncMap_[resType] = pluginLib;
573 }
574 
UnSubscribeSyncResource(const std::string & pluginLib,uint32_t resType)575 void PluginMgr::UnSubscribeSyncResource(const std::string& pluginLib, uint32_t resType)
576 {
577     if (pluginLib.empty()) {
578         RESSCHED_LOGE("%{public}s, PluginMgr failed, pluginLib is null.", __func__);
579         return;
580     }
581     std::lock_guard<std::mutex> autoLock(resTypeSyncMutex_);
582     auto iter = resTypeLibSyncMap_.find(resType);
583     if (iter == resTypeLibSyncMap_.end()) {
584         RESSCHED_LOGE("%{public}s, PluginMgr failed, res type has no plugin subscribe.", __func__);
585         return;
586     }
587     resTypeLibSyncMap_.erase(iter);
588 }
589 
DumpAllPlugin(std::string & result)590 void PluginMgr::DumpAllPlugin(std::string &result)
591 {
592     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
593     for (const auto& info : pluginInfoList) {
594         result.append(info.libPath).append(" ");
595         DumpPluginInfoAppend(result, info);
596     }
597 }
598 
DumpAllPluginConfig(std::string & result)599 void PluginMgr::DumpAllPluginConfig(std::string &result)
600 {
601     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
602     result.append("================Resource Schedule Plugin Switch================\n");
603     for (const auto& info : pluginInfoList) {
604         result.append(info.libPath).append(" ").append(std::to_string(info.switchOn)).append("\n");
605     }
606     configReader_->Dump(result);
607 }
608 
DumpOnePlugin(std::string & result,std::string pluginName,std::vector<std::string> & args)609 void PluginMgr::DumpOnePlugin(std::string &result, std::string pluginName, std::vector<std::string>& args)
610 {
611     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
612     auto pos = std::find_if(pluginInfoList.begin(),
613         pluginInfoList.end(), [&pluginName](PluginInfo &info) { return pluginName == info.libPath; });
614     if (pos == pluginInfoList.end()) {
615         result.append(" Error params.\n");
616         return;
617     }
618     if (args.size() == 0) {
619         result.append(pluginName).append(" ");
620         DumpPluginInfoAppend(result, *pos);
621     } else {
622         result.append("\n");
623         std::string errMsg = DumpInfoFromPlugin(result, pos->libPath, args);
624         if (errMsg != "") {
625             result.append(errMsg);
626         }
627     }
628 }
629 
DumpInfoFromPlugin(std::string & result,std::string libPath,std::vector<std::string> & args)630 std::string PluginMgr::DumpInfoFromPlugin(std::string& result, std::string libPath, std::vector<std::string>& args)
631 {
632     std::lock_guard<std::mutex> autoLock(pluginMutex_);
633     auto pluginLib = pluginLibMap_.find(libPath);
634     if (pluginLib == pluginLibMap_.end()) {
635         return "Error params.";
636     }
637 
638     if (pluginLib->second.onDumpFunc_) {
639         pluginLib->second.onDumpFunc_(args, result);
640         result.append("\n");
641     }
642     return "";
643 }
644 
DumpHelpFromPlugin(std::string & result)645 void PluginMgr::DumpHelpFromPlugin(std::string& result)
646 {
647     std::vector<std::string> args;
648     args.emplace_back("-h");
649     std::string pluginHelpMsg = "";
650     std::list<PluginInfo> pluginInfoList = pluginSwitch_->GetPluginSwitch();
651     for (auto &pluginInfo : pluginInfoList) {
652         DumpInfoFromPlugin(pluginHelpMsg, pluginInfo.libPath, args);
653     }
654     result.append(pluginHelpMsg);
655 }
656 
DumpPluginInfoAppend(std::string & result,PluginInfo info)657 void PluginMgr::DumpPluginInfoAppend(std::string &result, PluginInfo info)
658 {
659     if (info.switchOn) {
660         result.append(" | switch on\t");
661     } else {
662         result.append(" | switch off\t");
663     }
664     std::lock_guard<std::mutex> autoLock(pluginMutex_);
665     if (pluginLibMap_.find(info.libPath) != pluginLibMap_.end()) {
666         result.append(" | running now\n");
667     } else {
668         result.append(" | disabled\n");
669     }
670 }
671 
ClearResource()672 void PluginMgr::ClearResource()
673 {
674     {
675         std::lock_guard<std::mutex> autoLock(resTypeMutex_);
676         resTypeLibMap_.clear();
677     }
678     {
679         std::lock_guard<std::mutex> autoLock(resTypeSyncMutex_);
680         resTypeLibSyncMap_.clear();
681     }
682     {
683         std::lock_guard<std::mutex> autoLock(resTypeStrMutex_);
684         resTypeStrMap_.clear();
685     }
686     {
687         std::lock_guard<std::mutex> autoLock(linkJumpOptMutex_);
688         linkJumpOptSet_.clear();
689     }
690 }
691 
RepairPlugin(TimePoint endTime,const std::string & pluginLib,PluginLib libInfo)692 void PluginMgr::RepairPlugin(TimePoint endTime, const std::string& pluginLib, PluginLib libInfo)
693 {
694     auto& timeOutTime = pluginStat_[pluginLib].timeOutTime;
695     int32_t crash_time = (int32_t)((endTime - timeOutTime.front()) / std::chrono::milliseconds(1));
696     timeOutTime.emplace_back(endTime);
697     RESSCHED_LOGW("%{public}s %{public}s crash %{public}d times in %{public}d ms!", __func__,
698         pluginLib.c_str(), (int32_t)timeOutTime.size(), crash_time);
699     if ((int32_t)timeOutTime.size() >= MAX_PLUGIN_TIMEOUT_TIMES) {
700         if (crash_time < DISABLE_PLUGIN_TIME) {
701             // disable plugin forever
702             RESSCHED_LOGE("%{public}s, %{public}s disable it forever.", __func__, pluginLib.c_str());
703             if (libInfo.onPluginDisableFunc_) {
704                 libInfo.onPluginDisableFunc_();
705             }
706             HiSysEventWrite(HiviewDFX::HiSysEvent::Domain::RSS, "PLUGIN_DISABLE",
707                 HiSysEvent::EventType::FAULT, "plugin_name", pluginLib);
708             timeOutTime.clear();
709             pluginMutex_.lock();
710             pluginLibMap_.erase(pluginLib);
711             pluginMutex_.unlock();
712             return;
713         }
714 
715         timeOutTime.pop_front();
716     }
717 
718     if (libInfo.onPluginDisableFunc_ && libInfo.onPluginInitFunc_) {
719         RESSCHED_LOGW("%{public}s, %{public}s disable and enable it.", __func__, pluginLib.c_str());
720         libInfo.onPluginDisableFunc_();
721         libInfo.onPluginInitFunc_(const_cast<std::string&>(pluginLib));
722     }
723 }
724 
DispatchResourceToPluginSync(const std::list<std::string> & pluginList,const std::shared_ptr<ResData> & resData)725 void PluginMgr::DispatchResourceToPluginSync(const std::list<std::string>& pluginList,
726     const std::shared_ptr<ResData>& resData)
727 {
728     auto sortPluginList = SortPluginList(pluginList);
729     for (auto& pluginLib : sortPluginList) {
730         PluginLib libInfo;
731         {
732             std::lock_guard<std::mutex> autoLock(pluginMutex_);
733             auto itMap = pluginLibMap_.find(pluginLib);
734             if (itMap == pluginLibMap_.end()) {
735                 RESSCHED_LOGE("%{public}s, no plugin %{public}s !", __func__, pluginLib.c_str());
736                 continue;
737             }
738             libInfo = itMap->second;
739         }
740         OnDispatchResourceFunc pluginDispatchFunc = libInfo.onDispatchResourceFunc_;
741         if (!pluginDispatchFunc) {
742             RESSCHED_LOGE("%{public}s, no DispatchResourceFun !", __func__);
743             continue;
744         }
745 
746         StartTrace(HITRACE_TAG_APP, pluginLib);
747         auto beginTime = Clock::now();
748         pluginDispatchFunc(std::make_shared<ResData>(resData->resType, resData->value, resData->payload));
749         auto endTime = Clock::now();
750         FinishTrace(HITRACE_TAG_APP);
751         int32_t costTimeUs = (endTime - beginTime) / std::chrono::microseconds(1);
752         int32_t costTime = costTimeUs / 1000;
753         pluginStat_[pluginLib].Update(costTimeUs);
754 
755         if (costTime > DISPATCH_TIME_OUT) {
756             // dispatch resource use too long time, unload it
757             RESSCHED_LOGE("%{public}s, ERROR :%{public}s cost time(%{public}dms) over %{public}d ms! disable it.",
758                 __func__, pluginLib.c_str(), costTime, DISPATCH_TIME_OUT);
759             auto task = [endTime, pluginLib, libInfo, this] {
760                 RepairPlugin(endTime, pluginLib, libInfo);
761             };
762 #ifndef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
763             std::lock_guard<std::mutex> autoLock2(dispatcherHandlerMutex_);
764             if (dispatcher_) {
765                 dispatcher_->PostTask(task);
766             }
767 #endif
768         } else if (costTime > DISPATCH_WARNING_TIME) {
769             RESSCHED_LOGW("%{public}s, WARNING :%{public}s plugin cost time(%{public}dms) over %{public}d ms!",
770                 __func__, pluginLib.c_str(), costTime, DISPATCH_WARNING_TIME);
771         }
772     }
773 }
774 
775 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
DispatchResourceToPluginAsync(const std::list<std::string> & pluginList,const std::shared_ptr<ResData> & resData)776 void PluginMgr::DispatchResourceToPluginAsync(const std::list<std::string>& pluginList,
777     const std::shared_ptr<ResData>& resData)
778 {
779     for (auto& pluginLib : pluginList) {
780         if (disablePlugins_.find(pluginLib) != disablePlugins_.end()) {
781             continue;
782         }
783         PluginLib libInfo;
784         {
785             std::lock_guard<std::mutex> autoLock(pluginMutex_);
786             auto itMap = pluginLibMap_.find(pluginLib);
787             if (itMap == pluginLibMap_.end()) {
788                 RESSCHED_LOGE("%{public}s, no plugin %{public}s !", __func__, pluginLib.c_str());
789                 continue;
790             }
791             libInfo = itMap->second;
792         }
793         OnDispatchResourceFunc pluginDispatchFunc = libInfo.onDispatchResourceFunc_;
794         if (!pluginDispatchFunc) {
795             RESSCHED_LOGE("%{public}s, no DispatchResourceFun !", __func__);
796             continue;
797         }
798         std::lock_guard<ffrt::mutex> autoLock(dispatcherHandlerMutex_);
799         dispatchers_[pluginLib]->submit(
800             [pluginLib, resData, pluginDispatchFunc] {
801                 StartTrace(HITRACE_TAG_APP, pluginLib);
802                 pluginDispatchFunc(std::make_shared<ResData>(resData->resType, resData->value, resData->payload));
803                 FinishTrace(HITRACE_TAG_APP);
804             });
805     }
806 }
807 
EnablePluginIfResume(const std::string & pluginLib)808 void PluginMgr::EnablePluginIfResume(const std::string& pluginLib)
809 {
810     std::lock_guard<ffrt::mutex> autoLock(dispatcherHandlerMutex_);
811     ffrt_queue_cancel_all(*reinterpret_cast<ffrt_queue_t*>(dispatchers_[pluginLib].get()));
812     if (!IsPluginRunning(pluginLib)) {
813         disablePlugins_.erase(pluginLib);
814     } else {
815         StartTrace(HITRACE_TAG_APP, "Blocked plugin:" + pluginLib, -1);
816         RESSCHED_LOGI("plugin:%{public}s been locked!", pluginLib.c_str());
817         FinishTrace(HITRACE_TAG_APP);
818         ffrt::submit([lib = pluginLib]() {
819             PluginMgr::GetInstance().EnablePluginIfResume(lib);
820             }, {}, {}, ffrt::task_attr().delay(pluginBlockTime));
821     }
822 }
823 
HandlePluginTimeout(const std::string & pluginLib)824 void PluginMgr::HandlePluginTimeout(const std::string& pluginLib)
825 {
826     std::lock_guard<ffrt::mutex> autoLock(dispatcherHandlerMutex_);
827     ffrt_queue_cancel_all(*reinterpret_cast<ffrt_queue_t*>(dispatchers_[pluginLib].get()));
828     if (IsPluginRunning(pluginLib)) {
829         RESSCHED_LOGI("%{public}s, %{public}s has blocked task, stop dispatch resource to it!",
830             __func__, pluginLib.c_str());
831             disablePlugins_.insert(pluginLib);
832     } else {
833         RESSCHED_LOGI("%{public}s, %{public}s all tasks cancled!", __func__, pluginLib.c_str());
834     }
835 }
836 
RecordRinningStat(std::string pluginLib,bool isRunning)837 void PluginMgr::RecordRinningStat(std::string pluginLib, bool isRunning)
838 {
839     std::lock_guard<ffrt::mutex> autoLock(runningStatsMutex_);
840     runningStats_[pluginLib] = isRunning;
841 }
842 
IsPluginRunning(const std::string & pluginLib)843 bool PluginMgr::IsPluginRunning(const std::string& pluginLib)
844 {
845     std::lock_guard<ffrt::mutex> autoLock(runningStatsMutex_);
846     auto stateItem = runningStats_.find(pluginLib);
847     if (stateItem == runningStats_.end()) {
848         return false;
849     }
850     return stateItem->second;
851 }
852 #endif
853 
UnLoadPlugin()854 void PluginMgr::UnLoadPlugin()
855 {
856     std::lock_guard<std::mutex> autoLock(pluginMutex_);
857     // unload all plugin
858     for (const auto& [libPath, libInfo] : pluginLibMap_) {
859         if (!libInfo.onPluginDisableFunc_) {
860             continue;
861         }
862         libInfo.onPluginDisableFunc_();
863     }
864     // close all plugin handle
865     pluginLibMap_.clear();
866 }
867 
OnDestroy()868 void PluginMgr::OnDestroy()
869 {
870     UnLoadPlugin();
871     configReader_ = nullptr;
872     pluginSwitch_ = nullptr;
873     ClearResource();
874 #ifdef RESOURCE_SCHEDULE_SERVICE_WITH_FFRT_ENABLE
875     std::lock_guard<ffrt::mutex> autoLock(dispatcherHandlerMutex_);
876     dispatchers_.clear();
877 #else
878     std::lock_guard<std::mutex> autoLock(dispatcherHandlerMutex_);
879     if (dispatcher_) {
880         dispatcher_->RemoveAllEvents();
881         dispatcher_ = nullptr;
882     }
883 #endif
884 }
885 
SetResTypeStrMap(const std::map<uint32_t,std::string> & resTypeStr)886 void PluginMgr::SetResTypeStrMap(const std::map<uint32_t, std::string>& resTypeStr)
887 {
888     std::lock_guard<std::mutex> autoLock(resTypeStrMutex_);
889     resTypeStrMap_ = resTypeStr;
890 }
891 
SetBlockedTime(const int64_t time)892 void PluginMgr::SetBlockedTime(const int64_t time)
893 {
894     pluginBlockTime = time;
895 }
896 
SetLinkJumpOptSet(const std::unordered_set<std::string> linkJumpOptSet)897 void PluginMgr::SetLinkJumpOptSet(const std::unordered_set<std::string> linkJumpOptSet)
898 {
899     std::lock_guard<std::mutex> autoLock(linkJumpOptMutex_);
900     linkJumpOptSet_ = linkJumpOptSet;
901 }
902 
GetLinkJumpOptConfig(const std::string & bundleName,bool & isAllowedLinkJump)903 bool PluginMgr::GetLinkJumpOptConfig(const std::string& bundleName, bool& isAllowedLinkJump)
904 {
905     std::lock_guard<std::mutex> autoLock(linkJumpOptMutex_);
906     auto iter = linkJumpOptSet_.find(bundleName);
907     if (iter != linkJumpOptSet_.end()) {
908         isAllowedLinkJump = true;
909         return true;
910     }
911     return false;
912 }
913 
GetStrFromResTypeStrMap(uint32_t resType)914 std::string PluginMgr::GetStrFromResTypeStrMap(uint32_t resType)
915 {
916     std::lock_guard<std::mutex> autoLock(resTypeStrMutex_);
917     return resTypeStrMap_.count(resType) ? resTypeStrMap_.at(resType) : "UNKNOWN";
918 }
919 
SortPluginList(const std::list<std::string> & pluginList)920 std::list<std::string> PluginMgr::SortPluginList(const std::list<std::string>& pluginList)
921 {
922     auto sortPluginList = pluginList;
923     sortPluginList.sort([&](const std::string& a, const std::string& b) -> bool {
924         if (pluginStat_.find(a) == pluginStat_.end() || pluginStat_.find(b) == pluginStat_.end()) {
925             return false;
926         }
927         return pluginStat_[a].AverageTime() < pluginStat_[b].AverageTime();
928     });
929     return sortPluginList;
930 }
931 
InnerTimeUtil(const std::string & func,const std::string & plugin)932 PluginMgr::InnerTimeUtil::InnerTimeUtil(const std::string& func, const std::string& plugin)
933 {
934     beginTime_ = Clock::now();
935     functionName_ = func;
936     pluginName_ = plugin;
937 }
938 
~InnerTimeUtil()939 PluginMgr::InnerTimeUtil::~InnerTimeUtil()
940 {
941     auto endTime = Clock::now();
942     int32_t costTime = (endTime - beginTime_) / std::chrono::milliseconds(1);
943     RESSCHED_LOGD("%{public}s, %{public}s plugin cost time(%{public}d ms).",
944         functionName_.c_str(), pluginName_.c_str(), costTime);
945     if (costTime > DISPATCH_WARNING_TIME) {
946         RESSCHED_LOGW("%{public}s, WARNING :%{public}s plugin cost time(%{public}d ms) over %{public}d ms!",
947             functionName_.c_str(), pluginName_.c_str(), costTime, DISPATCH_WARNING_TIME);
948     }
949 }
950 extern "C" {
SetBlockedTime(const int64_t time)951     void SetBlockedTime(const int64_t time)
952     {
953         PluginMgr::GetInstance().SetBlockedTime(time);
954     }
955 }
956 } // namespace ResourceSchedule
957 } // namespace OHOS