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