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