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