1 /*
2 * Copyright (c) 2021-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 #include "hiview_platform.h"
16 #ifndef _WIN32
17 #include <dlfcn.h>
18 #include <sys/stat.h>
19 #include <sys/types.h>
20 #include <unistd.h>
21 #endif
22 #include <cinttypes>
23 #include <csignal>
24 #include <fstream>
25 #include <functional>
26
27 #include "app_event_publisher.h"
28 #include "app_event_publisher_factory.h"
29 #include "audit.h"
30 #include "backtrace_local.h"
31 #include "common_utils.h"
32 #include "defines.h"
33 #include "dispatch_rule_parser.h"
34 #include "dynamic_module.h"
35 #include "file_util.h"
36 #include "hiview_event_report.h"
37 #include "hiview_global.h"
38 #include "hiview_platform_config.h"
39 #include "hiview_logger.h"
40 #include "parameter_ex.h"
41 #include "param_event_manager.h"
42 #include "plugin_config.h"
43 #include "plugin_factory.h"
44 #include "string_util.h"
45 #include "time_util.h"
46 #include "xcollie/xcollie.h"
47
48 namespace OHOS {
49 namespace HiviewDFX {
50 namespace {
51 constexpr uint32_t AID_SYSTEM = 1000;
52 static const char VERSION[] = "1.0.0.0";
53 static const char SEPARATOR_VERSION[] = " ";
54 static const char RECORDER_VERSION[] = "01.00";
55 static const char PLUGIN_CONFIG_NAME[] = "plugin_config";
56 static const char HIVIEW_PID_FILE_NAME[] = "hiview.pid";
57 static const char DEFAULT_CONFIG_DIR[] = "/system/etc/hiview/";
58 static const char PIPELINE_RULE_CONFIG_DIR[] = "/system/etc/hiview/dispatch_rule/";
59 static const char DISPATCH_RULE_CONFIG_DIR[] = "/system/etc/hiview/listener_rule/";
60 static const char DEFAULT_WORK_DIR[] = "/data/log/hiview/";
61 static const char DEFAULT_COMMERCIAL_WORK_DIR[] = "/log/LogService/";
62 static const char DEFAULT_PERSIST_DIR[] = "/log/hiview/";
63 static const char LIB_SEARCH_DIR[] = "/system/lib/";
64 static const char LIB64_SEARCH_DIR[] = "/system/lib64/";
65 }
66 DEFINE_LOG_TAG("HiView-HiviewPlatform");
HiviewPlatform()67 HiviewPlatform::HiviewPlatform()
68 : isReady_(false),
69 defaultConfigDir_(DEFAULT_CONFIG_DIR),
70 defaultWorkDir_(DEFAULT_WORK_DIR),
71 defaultCommercialWorkDir_(DEFAULT_COMMERCIAL_WORK_DIR),
72 defaultPersistDir_(DEFAULT_PERSIST_DIR),
73 defaultConfigName_(PLUGIN_CONFIG_NAME),
74 unorderQueue_(nullptr),
75 sharedWorkLoop_(nullptr)
76 {
77 dynamicLibSearchDir_.push_back(LIB_SEARCH_DIR);
78 dynamicLibSearchDir_.push_back(LIB64_SEARCH_DIR);
79 }
80
~HiviewPlatform()81 HiviewPlatform::~HiviewPlatform()
82 {
83 if (unorderQueue_ != nullptr) {
84 unorderQueue_->Stop();
85 }
86
87 if (sharedWorkLoop_ != nullptr) {
88 sharedWorkLoop_->StopLoop();
89 }
90 HiviewGlobal::ReleaseInstance();
91 }
92
SetMaxProxyIdleTime(time_t idleTime)93 void HiviewPlatform::SetMaxProxyIdleTime(time_t idleTime)
94 {
95 maxIdleTime_ = idleTime;
96 }
97
SetCheckProxyIdlePeriod(time_t period)98 void HiviewPlatform::SetCheckProxyIdlePeriod(time_t period)
99 {
100 checkIdlePeriod_ = period;
101 }
102
InitEnvironment(const std::string & platformConfigDir)103 bool HiviewPlatform::InitEnvironment(const std::string& platformConfigDir)
104 {
105 // wait util the samgr is ready
106 if (auto res = Parameter::WaitParamSync("bootevent.samgr.ready", "true", 5); res != 0) { // timeout is 5s
107 HIVIEW_LOGE("Fail to wait the samgr, err=%{public}d", res);
108 return false;
109 }
110 CreateWorkingDirectories(platformConfigDir);
111
112 // update beta config
113 UpdateBetaConfigIfNeed();
114
115 // check whether hiview is already started
116 ExitHiviewIfNeed();
117
118 std::string cfgPath = GetPluginConfigPath();
119 PluginConfig config(cfgPath);
120 if (!config.StartParse()) {
121 HIVIEW_LOGE("Fail to parse plugin config. exit!, cfgPath %{public}s", cfgPath.c_str());
122 return false;
123 }
124 StartPlatformDispatchQueue();
125
126 // init global context helper, remove in the future
127 HiviewGlobal::CreateInstance(static_cast<HiviewContext&>(*this));
128 LoadBusinessPlugin(config);
129
130 // start load plugin bundles
131 LoadPluginBundles();
132
133 // maple delay start eventsource
134 for (const auto& plugin : eventSourceList_) {
135 auto sharedSource = std::static_pointer_cast<EventSource>(plugin);
136 if (sharedSource == nullptr) {
137 HIVIEW_LOGE("Fail to cast plugin to event source!");
138 continue;
139 }
140 StartEventSource(sharedSource);
141 }
142 eventSourceList_.clear();
143 isReady_ = true;
144 NotifyPluginReady();
145 ScheduleCheckUnloadablePlugins();
146 OHOS::Singleton<ParamEventManager>::GetInstance().SubscriberEvent();
147 if (Parameter::IsBetaVersion()) {
148 AddWatchDog();
149 }
150 return true;
151 }
152
SaveStack()153 void HiviewPlatform::SaveStack()
154 {
155 if (hasDumpStack_) {
156 return;
157 }
158
159 std::string workPath = HiviewGlobal::GetInstance()->GetHiViewDirectory(
160 HiviewContext::DirectoryType::WORK_DIRECTORY);
161 std::string stackPath = FileUtil::IncludeTrailingPathDelimiter(workPath) + "hiview_stack.log";
162 std::string stackTrace = GetProcessStacktrace();
163 HIVIEW_LOGI("XCollieCallback: %{public}zu", stackTrace.length());
164 if (!FileUtil::SaveStringToFile(stackPath, stackTrace)) {
165 HIVIEW_LOGE("XCollieCallback: save stack fail.");
166 return;
167 }
168
169 if (chmod(stackPath.c_str(), FileUtil::FILE_PERM_600) != 0) {
170 HIVIEW_LOGE("XCollieCallback: chmod fail.");
171 }
172 hasDumpStack_ = true;
173 }
174
AddWatchDog()175 void HiviewPlatform::AddWatchDog()
176 {
177 constexpr int HICOLLIE_TIMER_SECOND = 60 * 5;
178 watchDogTimer_ = HiviewDFX::XCollie::GetInstance().SetTimer("hiview_watchdog", HICOLLIE_TIMER_SECOND,
179 [this](void *) { SaveStack(); }, nullptr, HiviewDFX::XCOLLIE_FLAG_NOOP);
180
181 auto task = [this] {
182 HiviewDFX::XCollie::GetInstance().CancelTimer(watchDogTimer_);
183 watchDogTimer_ = HiviewDFX::XCollie::GetInstance().SetTimer("hiview_watchdog", HICOLLIE_TIMER_SECOND,
184 [this](void *) { SaveStack(); }, nullptr, HiviewDFX::XCOLLIE_FLAG_NOOP);
185 };
186 constexpr int RESET_TIMER_SECOND = 60;
187 sharedWorkLoop_->AddTimerEvent(nullptr, nullptr, task, RESET_TIMER_SECOND, true);
188 HIVIEW_LOGI("add watch dog task");
189 }
190
CreateWorkingDirectories(const std::string & platformConfigDir)191 void HiviewPlatform::CreateWorkingDirectories(const std::string& platformConfigDir)
192 {
193 HiviewPlatformConfig platformConfig = HiviewPlatformConfig(platformConfigDir);
194 HiviewPlatformConfig::PlatformConfigInfo platformConfigInfo;
195 bool state = platformConfig.ParsesConfig(platformConfigInfo);
196 if (state) {
197 if (platformConfigInfo.defaultPluginConfigName != "") {
198 defaultConfigName_ = platformConfigInfo.defaultPluginConfigName;
199 }
200 if (FileUtil::IsDirectory(platformConfigInfo.commercialWorkDir)) {
201 defaultCommercialWorkDir_ = platformConfigInfo.commercialWorkDir;
202 }
203 if (platformConfigInfo.dynamicLib64SearchDir != ""
204 || platformConfigInfo.dynamicLibSearchDir != "") {
205 dynamicLibSearchDir_.clear();
206 }
207 if (platformConfigInfo.dynamicLib64SearchDir != "") {
208 dynamicLibSearchDir_.push_back(platformConfigInfo.dynamicLib64SearchDir);
209 }
210 if (platformConfigInfo.dynamicLibSearchDir != "") {
211 dynamicLibSearchDir_.push_back(platformConfigInfo.dynamicLibSearchDir);
212 }
213 ValidateAndCreateDirectories(platformConfigInfo.pluginConfigFileDir,
214 platformConfigInfo.workDir,
215 platformConfigInfo.persistDir);
216 }
217 }
218
UpdateBetaConfigIfNeed()219 void HiviewPlatform::UpdateBetaConfigIfNeed()
220 {
221 }
222
LoadBusinessPlugin(const PluginConfig & config)223 void HiviewPlatform::LoadBusinessPlugin(const PluginConfig& config)
224 {
225 // start to load plugin
226 // 1. create plugin
227 auto const& pluginInfoList = config.GetPluginInfoList();
228 for (auto const& pluginInfo : pluginInfoList) {
229 HIVIEW_LOGI("Start to create plugin %{public}s delay:%{public}d", pluginInfo.name.c_str(),
230 pluginInfo.loadDelay);
231 if (pluginInfo.loadDelay > 0) {
232 auto task = std::bind(&HiviewPlatform::ScheduleCreateAndInitPlugin, this, pluginInfo);
233 sharedWorkLoop_->AddTimerEvent(nullptr, nullptr, task, pluginInfo.loadDelay, false);
234 } else {
235 CreatePlugin(pluginInfo);
236 }
237 }
238 // 2. create pipelines
239 auto const& pipelineInfoList = config.GetPipelineInfoList();
240 for (auto const& pipelineInfo : pipelineInfoList) {
241 HIVIEW_LOGI("Start to create pipeline %{public}s", pipelineInfo.name.c_str());
242 CreatePipeline(pipelineInfo);
243 }
244
245 // 3. bind pipeline and call onload of event source
246 for (auto const& pluginInfo : pluginInfoList) {
247 HIVIEW_LOGI("Start to Load plugin %{public}s", pluginInfo.name.c_str());
248 InitPlugin(config, pluginInfo);
249 }
250
251 // 4. delay start EventSource
252 for (auto const& pluginInfo : pluginInfoList) {
253 if (pluginInfo.isEventSource) {
254 HIVIEW_LOGI("Start to Load eventSource %{public}s", pluginInfo.name.c_str());
255 auto& plugin = pluginMap_[pluginInfo.name];
256 auto sharedSource = std::static_pointer_cast<EventSource>(plugin);
257 if (sharedSource == nullptr) {
258 HIVIEW_LOGE("Fail to cast plugin to event source!");
259 continue;
260 }
261 eventSourceList_.push_back(plugin);
262 }
263 }
264
265 CleanupUnusedResources();
266 }
267
SplitBundleNameFromPath(const std::string & filePath)268 std::string HiviewPlatform::SplitBundleNameFromPath(const std::string& filePath)
269 {
270 // the path should be like /system/etc/hiview/bundleName_plugin_config
271 auto pos = filePath.find_last_of("/\\");
272 if (pos == std::string::npos) {
273 return "";
274 }
275
276 std::string fileName = filePath.substr(pos + 1);
277 pos = fileName.find(defaultConfigName_);
278 if (pos == std::string::npos || pos == 0) {
279 return "";
280 }
281
282 pos = fileName.find_first_of("_");
283 if (pos == std::string::npos) {
284 return "";
285 }
286
287 return fileName.substr(0, pos);
288 }
289
SearchPluginBundle(const std::string & name) const290 std::string HiviewPlatform::SearchPluginBundle(const std::string& name) const
291 {
292 for (const auto& pathPrefix : dynamicLibSearchDir_) {
293 std::string bundlePath = pathPrefix + GetDynamicLibName(name, true);
294 printf("bundlePath is %s\n", bundlePath.c_str());
295 if (FileUtil::FileExists(bundlePath)) {
296 return bundlePath;
297 }
298 }
299 return "";
300 }
301
LoadPluginBundle(const std::string & bundleName,const std::string & filePath)302 void HiviewPlatform::LoadPluginBundle(const std::string& bundleName, const std::string& filePath)
303 {
304 PluginConfig config(filePath);
305 if (!config.StartParse()) {
306 HIVIEW_LOGE("Fail to parse plugin config %{public}s, filePath is %{public}s",
307 bundleName.c_str(), filePath.c_str());
308 return;
309 }
310
311 std::string bundlePath = SearchPluginBundle(bundleName);
312 if (bundlePath == "") {
313 HIVIEW_LOGE("bundleName: %{public}s doesn't exist", bundleName.c_str());
314 return;
315 }
316 auto handle = LoadModule(bundlePath);
317 if (handle == DynamicModuleDefault) {
318 return;
319 }
320
321 LoadBusinessPlugin(config);
322 std::shared_ptr<PluginBundle> bundle = std::make_shared<PluginBundle>(bundleName, config, handle);
323 pluginBundleInfos_.insert(std::pair<std::string, std::shared_ptr<PluginBundle>>(bundleName, bundle));
324 }
325
LoadPluginBundles()326 void HiviewPlatform::LoadPluginBundles()
327 {
328 std::vector<std::string> configFiles;
329 FileUtil::GetDirFiles(defaultConfigDir_, configFiles);
330 sort(configFiles.begin(), configFiles.end()); // guarantee DFT plugins config parse first
331 for (const auto& filePath : configFiles) {
332 auto bundleName = SplitBundleNameFromPath(filePath);
333 if (bundleName.empty()) {
334 continue;
335 }
336 LoadPluginBundle(bundleName, filePath);
337 }
338 }
339
ProcessArgsRequest(int argc,char * argv[])340 void HiviewPlatform::ProcessArgsRequest(int argc, char* argv[])
341 {
342 #ifndef _WIN32
343 umask(0002); // 0002 is block other write permissions, -------w-
344 signal(SIGPIPE, SIG_IGN);
345 int ch = -1;
346 while ((ch = getopt(argc, argv, "v")) != -1) {
347 if (ch == 'v') {
348 HIVIEW_LOGI("hiview version: %s%s%s", VERSION, SEPARATOR_VERSION, RECORDER_VERSION);
349 printf("hiview version: %s%s%s\n", VERSION, SEPARATOR_VERSION, RECORDER_VERSION);
350 _exit(1);
351 }
352 }
353 #endif // !_WIN32
354 }
355
LoadDynamicPlugin(const std::string & name) const356 DynamicModule HiviewPlatform::LoadDynamicPlugin(const std::string& name) const
357 {
358 // if the plugin Class is AbcPlugin, the so name should be libabcplugin.z.so
359 std::string dynamicPluginName = GetDynamicLibName(name, true);
360 auto handle = LoadModule(dynamicPluginName.c_str());
361 if (handle == nullptr) {
362 // retry load library
363 dynamicPluginName = GetDynamicLibName(name, false);
364 handle = LoadModule(dynamicPluginName.c_str());
365 }
366 return handle;
367 }
368
GetDynamicLibName(const std::string & name,bool hasOhosSuffix) const369 std::string HiviewPlatform::GetDynamicLibName(const std::string& name, bool hasOhosSuffix) const
370 {
371 #ifdef __HIVIEW_OHOS__
372 std::string tmp = "lib" + name;
373 if (hasOhosSuffix) {
374 tmp.append(".z.so");
375 } else {
376 tmp.append(".so");
377 }
378
379 for (unsigned i = 0; i < tmp.length(); i++) {
380 tmp[i] = std::tolower(tmp[i]);
381 }
382 return tmp;
383 #elif defined(_WIN32)
384 std::string dynamicLibName = "";
385 dynamicLibName.append(name);
386 dynamicLibName.append(".dll");
387 return dynamicLibName;
388 #else
389 // dynamic plugins feature is only enabled in double framework version
390 (void)hasOhosSuffix;
391 HIVIEW_LOGI("could not load dynamic lib %s, not supported yet.", name.c_str());
392 return "";
393 #endif
394 }
395
CreatePlugin(const PluginConfig::PluginInfo & pluginInfo)396 void HiviewPlatform::CreatePlugin(const PluginConfig::PluginInfo& pluginInfo)
397 {
398 if (pluginInfo.name.empty()) {
399 return;
400 }
401 if (pluginMap_.find(pluginInfo.name) != pluginMap_.end()) {
402 HiviewEventReport::ReportPluginLoad(pluginInfo.name, PluginEventSpace::LOAD_DUPLICATE_NAME);
403 HIVIEW_LOGW("plugin %{public}s already exists! create plugin failed", pluginInfo.name.c_str());
404 return;
405 }
406 // the dynamic plugin will register it's constructor to factory automatically after opening the binary
407 // if we get null in factory, it means something must go wrong.
408 DynamicModule handle = DynamicModuleDefault;
409 if (!pluginInfo.isStatic) {
410 handle = LoadDynamicPlugin(pluginInfo.name);
411 }
412
413 std::shared_ptr<PluginRegistInfo> registInfo = PluginFactory::GetGlobalPluginInfo(pluginInfo.name);
414 if (registInfo == nullptr) {
415 HiviewEventReport::ReportPluginLoad(pluginInfo.name, PluginEventSpace::LOAD_UNREGISTERED);
416 if (handle != DynamicModuleDefault) {
417 UnloadModule(handle);
418 }
419 return;
420 }
421
422 std::shared_ptr<Plugin> plugin = nullptr;
423 if (registInfo->needCreateProxy) {
424 plugin = std::make_shared<PluginProxy>();
425 plugin->SetType(Plugin::PluginType::PROXY);
426 (std::static_pointer_cast<PluginProxy>(plugin))->SetPluginConfig(pluginInfo);
427 } else {
428 plugin = registInfo->getPluginObject();
429 }
430
431 // app event publisher
432 if (AppEventPublisherFactory::IsPublisher(pluginInfo.name)) {
433 auto appEventHandler = std::make_shared<AppEventHandler>();
434 (std::static_pointer_cast<AppEventPublisher>(plugin))->AddAppEventHandler(appEventHandler);
435 }
436
437 // Initialize plugin parameters
438 plugin->SetName(pluginInfo.name);
439 plugin->SetHandle(handle);
440 plugin->SetHiviewContext(this);
441
442 // call preload, check whether we should release at once
443 if (!plugin->ReadyToLoad()) {
444 // if the plugin is a dynamic loaded library, the handle will be closed when calling the destructor
445 return;
446 }
447 // hold the global reference of the plugin
448 pluginMap_[pluginInfo.name] = std::move(plugin);
449 }
450
CreatePipeline(const PluginConfig::PipelineInfo & pipelineInfo)451 void HiviewPlatform::CreatePipeline(const PluginConfig::PipelineInfo& pipelineInfo)
452 {
453 if (pipelines_.find(pipelineInfo.name) != pipelines_.end()) {
454 HIVIEW_LOGW("pipeline %{public}s already exists! create pipeline failed", pipelineInfo.name.c_str());
455 return;
456 }
457
458 std::list<std::weak_ptr<Plugin>> pluginList;
459 for (const auto& pluginName : pipelineInfo.pluginNameList) {
460 if (pluginMap_.find(pluginName) == pluginMap_.end()) {
461 HIVIEW_LOGI("could not find plugin(%{public}s), skip adding to pipeline(%{public}s).",
462 pluginName.c_str(), pipelineInfo.name.c_str());
463 continue;
464 }
465 pluginList.push_back(pluginMap_[pluginName]);
466 }
467
468 std::shared_ptr<Pipeline> pipeline = std::make_shared<Pipeline>(pipelineInfo.name, pluginList);
469 pipelines_[pipelineInfo.name] = std::move(pipeline);
470
471 std::string configPath = PIPELINE_RULE_CONFIG_DIR + pipelineInfo.name;
472 HIVIEW_LOGI("config file=%{public}s", configPath.c_str());
473 if (!FileUtil::FileExists(configPath)) {
474 HIVIEW_LOGI("file=%{public}s does not exist", configPath.c_str());
475 return;
476 }
477 DispatchRuleParser ruleParser(configPath);
478 if (auto rule = ruleParser.GetRule(); rule != nullptr) {
479 pipelineRules_[pipelineInfo.name] = rule;
480 } else {
481 HIVIEW_LOGE("failed to parse config file=%{public}s", configPath.c_str());
482 }
483 }
484
InitPlugin(const PluginConfig & config __UNUSED,const PluginConfig::PluginInfo & pluginInfo)485 void HiviewPlatform::InitPlugin(const PluginConfig& config __UNUSED, const PluginConfig::PluginInfo& pluginInfo)
486 {
487 if (pluginMap_.find(pluginInfo.name) == pluginMap_.end()) {
488 return;
489 }
490 auto& plugin = pluginMap_[pluginInfo.name];
491
492 if (pluginInfo.workHandlerType == "thread") {
493 auto workLoop = GetAvailableWorkLoop(pluginInfo.workHandlerName);
494 plugin->BindWorkLoop(workLoop);
495 }
496
497 uint64_t beginTime = TimeUtil::GenerateTimestamp();
498 plugin->OnLoad();
499
500 if (std::string configPath = DISPATCH_RULE_CONFIG_DIR + pluginInfo.name; FileUtil::FileExists(configPath)) {
501 HIVIEW_LOGI("config file=%{public}s", configPath.c_str());
502 DispatchRuleParser ruleParser(configPath);
503 if (auto rule = ruleParser.GetRule(); rule != nullptr) {
504 AddDispatchInfo(std::weak_ptr<Plugin>(plugin), rule->typeList,
505 rule->eventList, rule->tagList, rule->domainRuleMap);
506 } else {
507 HIVIEW_LOGE("failed to parse config file=%{public}s", configPath.c_str());
508 }
509 }
510
511 if (pluginInfo.isEventSource) {
512 auto sharedSource = std::static_pointer_cast<EventSource>(plugin);
513 if (sharedSource == nullptr) {
514 HIVIEW_LOGE("Fail to cast plugin to event source!");
515 return;
516 }
517 for (const auto& pipelineName : pluginInfo.pipelineNameList) {
518 sharedSource->AddPipeline(pipelines_[pipelineName]);
519 }
520 }
521
522 if (plugin->GetType() == Plugin::PluginType::PROXY) {
523 std::shared_ptr<PluginRegistInfo> registInfo = PluginFactory::GetGlobalPluginInfo(pluginInfo.name);
524 if (registInfo != nullptr && registInfo->needStartupLoading) {
525 std::shared_ptr<PluginProxy> pluginProxy = std::static_pointer_cast<PluginProxy>(plugin);
526 pluginProxy->LoadPluginIfNeed();
527 }
528 }
529
530 uint64_t endTime = TimeUtil::GenerateTimestamp();
531 uint64_t loadDuration = endTime > beginTime ? (endTime - beginTime) : 0;
532 HIVIEW_LOGI("Plugin %{public}s loadtime:%{public}" PRIu64 ".", pluginInfo.name.c_str(), loadDuration);
533 HiviewEventReport::ReportPluginLoad(pluginInfo.name, PluginEventSpace::LOAD_SUCCESS, loadDuration);
534 }
535
NotifyPluginReady()536 void HiviewPlatform::NotifyPluginReady()
537 {
538 auto event = std::make_shared<Event>("platform");
539 event->messageType_ = Event::MessageType::PLUGIN_MAINTENANCE;
540 event->eventId_ = Event::EventId::PLUGIN_LOADED;
541 PostUnorderedEvent(nullptr, event);
542 }
543
StartEventSource(std::shared_ptr<EventSource> source)544 void HiviewPlatform::StartEventSource(std::shared_ptr<EventSource> source)
545 {
546 auto workLoop = source->GetWorkLoop();
547 auto name = source->GetName();
548 if (workLoop == nullptr) {
549 HIVIEW_LOGW("No work loop available, start event source[%s] in current thead!", name.c_str());
550 source->StartEventSource();
551 } else {
552 HIVIEW_LOGI("Start event source[%s] in thead[%s].", name.c_str(), workLoop->GetName().c_str());
553 auto task = std::bind(&EventSource::StartEventSource, source.get());
554 workLoop->AddEvent(nullptr, nullptr, task);
555 }
556 HIVIEW_LOGI("Start event source[%s] in current thead done.", name.c_str());
557 }
558
559 // only call from main thread
GetAvailableWorkLoop(const std::string & name)560 std::shared_ptr<EventLoop> HiviewPlatform::GetAvailableWorkLoop(const std::string& name)
561 {
562 auto it = privateWorkLoopMap_.find(name);
563 if (it != privateWorkLoopMap_.end()) {
564 return it->second;
565 }
566
567 auto privateLoop = std::make_shared<EventLoop>(name);
568 if (privateLoop != nullptr) {
569 privateWorkLoopMap_.insert(std::make_pair(name, privateLoop));
570 privateLoop->StartLoop();
571 }
572 return privateLoop;
573 }
574
CleanupUnusedResources()575 void HiviewPlatform::CleanupUnusedResources()
576 {
577 auto iter = pluginMap_.begin();
578 while (iter != pluginMap_.end()) {
579 if (iter->second == nullptr) {
580 iter = pluginMap_.erase(iter);
581 } else {
582 ++iter;
583 }
584 }
585 }
586
ScheduleCreateAndInitPlugin(const PluginConfig::PluginInfo & pluginInfo)587 void HiviewPlatform::ScheduleCreateAndInitPlugin(const PluginConfig::PluginInfo& pluginInfo)
588 {
589 // only support thread type
590 CreatePlugin(pluginInfo);
591 if (pluginMap_.find(pluginInfo.name) == pluginMap_.end()) {
592 return;
593 }
594 auto& plugin = pluginMap_[pluginInfo.name];
595
596 if (pluginInfo.workHandlerType == "thread") {
597 auto workLoop = GetAvailableWorkLoop(pluginInfo.workHandlerName);
598 plugin->BindWorkLoop(workLoop);
599 }
600 plugin->OnLoad();
601 }
602
StartLoop()603 void HiviewPlatform::StartLoop()
604 {
605 // empty implementation
606 }
607
StartPlatformDispatchQueue()608 void HiviewPlatform::StartPlatformDispatchQueue()
609 {
610 if (unorderQueue_ == nullptr) {
611 unorderQueue_ = std::make_shared<EventDispatchQueue>("plat_unorder", Event::ManageType::UNORDERED, this);
612 unorderQueue_->Start();
613 }
614
615 if (sharedWorkLoop_ == nullptr) {
616 sharedWorkLoop_ = std::make_shared<EventLoop>("plat_shared");
617 sharedWorkLoop_->StartLoop();
618 }
619 }
620
GetPipelineSequenceByName(const std::string & name)621 std::list<std::weak_ptr<Plugin>> HiviewPlatform::GetPipelineSequenceByName(const std::string& name)
622 {
623 if (!isReady_) {
624 return std::list<std::weak_ptr<Plugin>>();
625 }
626
627 auto it = pipelines_.find(name);
628 if (it != pipelines_.end()) {
629 return it->second->GetProcessSequence();
630 }
631 return std::list<std::weak_ptr<Plugin>>(0);
632 }
633
PostUnorderedEvent(std::shared_ptr<Plugin> plugin,std::shared_ptr<Event> event)634 void HiviewPlatform::PostUnorderedEvent(std::shared_ptr<Plugin> plugin, std::shared_ptr<Event> event)
635 {
636 if (!isReady_) {
637 return;
638 }
639
640 if (plugin == nullptr) {
641 HIVIEW_LOGI("maybe platform send event");
642 }
643
644 if (unorderQueue_ != nullptr && event != nullptr) {
645 event->processType_ = Event::ManageType::UNORDERED;
646 unorderQueue_->Enqueue(event);
647 }
648 }
649
RegisterUnorderedEventListener(std::weak_ptr<EventListener> listener)650 void HiviewPlatform::RegisterUnorderedEventListener(std::weak_ptr<EventListener> listener)
651 {
652 auto ptr = listener.lock();
653 if (ptr == nullptr) {
654 return;
655 }
656 auto name = ptr->GetListenerName();
657 auto itListenerInfo = listeners_.find(name);
658 if (itListenerInfo == listeners_.end()) {
659 auto tmp = std::make_shared<ListenerInfo>();
660 tmp->listener_ = listener;
661 listeners_[name] = tmp;
662 } else {
663 auto tmp = listeners_[name];
664 tmp->listener_ = listener;
665 }
666 }
667
PostSyncEventToTarget(std::shared_ptr<Plugin> caller,const std::string & calleeName,std::shared_ptr<Event> event)668 bool HiviewPlatform::PostSyncEventToTarget(std::shared_ptr<Plugin> caller, const std::string& calleeName,
669 std::shared_ptr<Event> event)
670 {
671 if (!isReady_) {
672 return false;
673 }
674
675 auto it = pluginMap_.find(calleeName);
676 if (it == pluginMap_.end()) {
677 return false;
678 }
679
680 auto callee = it->second;
681 if (callee == nullptr) {
682 return false;
683 }
684
685 auto workLoop = callee->GetWorkLoop();
686 std::future<bool> ret;
687 if (workLoop == nullptr) {
688 ret = sharedWorkLoop_->AddEventForResult(callee, event);
689 } else {
690 ret = workLoop->AddEventForResult(callee, event);
691 }
692 return ret.get();
693 }
694
PostAsyncEventToTarget(std::shared_ptr<Plugin> caller,const std::string & calleeName,std::shared_ptr<Event> event)695 void HiviewPlatform::PostAsyncEventToTarget(std::shared_ptr<Plugin> caller, const std::string& calleeName,
696 std::shared_ptr<Event> event)
697 {
698 if (!isReady_) {
699 return;
700 }
701
702 auto it = pluginMap_.find(calleeName);
703 if (it == pluginMap_.end()) {
704 return;
705 }
706
707 auto callee = it->second;
708 if (callee == nullptr) {
709 return;
710 }
711
712 auto workLoop = callee->GetWorkLoop();
713 if (workLoop == nullptr) {
714 sharedWorkLoop_->AddEvent(callee, event);
715 } else {
716 workLoop->AddEvent(callee, event);
717 }
718 HIVIEW_LOGI("Post async event to %{public}s successfully", calleeName.c_str());
719 }
720
GetSharedWorkLoop()721 std::shared_ptr<EventLoop> HiviewPlatform::GetSharedWorkLoop()
722 {
723 return sharedWorkLoop_;
724 }
725
IsReady()726 bool HiviewPlatform::IsReady()
727 {
728 return isReady_;
729 }
730
RequestUnloadPlugin(std::shared_ptr<Plugin> caller)731 void HiviewPlatform::RequestUnloadPlugin(std::shared_ptr<Plugin> caller)
732 {
733 if (caller == nullptr) {
734 HiviewEventReport::ReportPluginUnload("", PluginEventSpace::UNLOAD_INVALID);
735 return;
736 }
737
738 std::string name = caller->GetName();
739 auto task = std::bind(&HiviewPlatform::UnloadPlugin, this, name);
740 // delay 1s to unload target plugin
741 const int unloadDelay = 1;
742 sharedWorkLoop_->AddTimerEvent(nullptr, nullptr, task, unloadDelay, false);
743 }
744
UnloadPlugin(const std::string & name)745 void HiviewPlatform::UnloadPlugin(const std::string& name)
746 {
747 auto it = pluginMap_.find(name);
748 if (it == pluginMap_.end()) {
749 HiviewEventReport::ReportPluginUnload(name, PluginEventSpace::UNLOAD_NOT_FOUND);
750 return;
751 }
752 auto target = it->second;
753 if (target == nullptr) {
754 HIVIEW_LOGW("Plugin %{public}s target is null.", name.c_str());
755 return;
756 }
757 auto count = target.use_count();
758 if (count > 2) { // two counts for 1.current ref 2.map holder ref
759 HIVIEW_LOGW("Plugin %{public}s has more refs(%{public}ld), may caused by unfinished task. unload failed.",
760 name.c_str(), count);
761 HiviewEventReport::ReportPluginUnload(name, PluginEventSpace::UNLOAD_IN_USE);
762 return;
763 }
764 pluginMap_.erase(name);
765 target->OnUnload();
766
767 // By default, reloading is not supported after unloading!
768 PluginFactory::UnregisterPlugin(target->GetName());
769 // report unloading success event
770 HiviewEventReport::ReportPluginUnload(name, PluginEventSpace::UNLOAD_SUCCESS);
771
772 auto looper = target->GetWorkLoop();
773 if (looper == nullptr) {
774 return;
775 }
776 if (looper.use_count() <= 3) { // three counts for 1.current ref 2.plugin ref 3.map holder ref
777 auto looperName = looper->GetRawName();
778 HIVIEW_LOGI("%{public}s has refs(%{public}ld).", looperName.c_str(), looper.use_count());
779 looper->StopLoop();
780 privateWorkLoopMap_.erase(looperName);
781 HIVIEW_LOGI("Stop %{public}s done.", looperName.c_str());
782 }
783 }
784
GetHiViewDirectory(HiviewContext::DirectoryType type)785 std::string HiviewPlatform::GetHiViewDirectory(HiviewContext::DirectoryType type)
786 {
787 switch (type) {
788 case HiviewContext::DirectoryType::CONFIG_DIRECTORY:
789 return defaultConfigDir_;
790 case HiviewContext::DirectoryType::WORK_DIRECTORY:
791 return defaultWorkDir_;
792 case HiviewContext::DirectoryType::PERSIST_DIR:
793 return defaultPersistDir_;
794 default:
795 break;
796 }
797 return "";
798 }
799
ValidateAndCreateDirectory(std::string & defaultPath,const std::string & realPath)800 void HiviewPlatform::ValidateAndCreateDirectory(std::string& defaultPath, const std::string& realPath)
801 {
802 if (defaultPath != realPath) {
803 defaultPath = realPath;
804 }
805 if (FileUtil::IsDirectory(defaultPath)) {
806 return;
807 }
808 FileUtil::CreateDirWithDefaultPerm(defaultPath, AID_SYSTEM, AID_SYSTEM);
809 }
810
ValidateAndCreateDirectories(const std::string & localPath,const std::string & workPath,const std::string & persistPath)811 void HiviewPlatform::ValidateAndCreateDirectories(const std::string& localPath, const std::string& workPath,
812 const std::string& persistPath)
813 {
814 ValidateAndCreateDirectory(defaultConfigDir_, localPath);
815 ValidateAndCreateDirectory(defaultWorkDir_, workPath);
816 ValidateAndCreateDirectory(defaultPersistDir_, persistPath);
817 }
818
819 #ifndef _WIN32
ExitHiviewIfNeed()820 void HiviewPlatform::ExitHiviewIfNeed()
821 {
822 int selfPid = getpid();
823 std::string selfProcName = CommonUtils::GetProcNameByPid(selfPid);
824 if (selfProcName != "hiview") {
825 return;
826 }
827
828 std::string pidFile = defaultWorkDir_ + "/" + std::string(HIVIEW_PID_FILE_NAME);
829 if (!FileUtil::FileExists(pidFile)) {
830 return;
831 }
832
833 std::string content;
834 FileUtil::LoadStringFromFile(pidFile, content);
835 int32_t pid = -1;
836 if (!StringUtil::StrToInt(content, pid)) {
837 return;
838 }
839
840 std::string procName = CommonUtils::GetProcNameByPid(pid);
841 if (procName == "hiview") {
842 printf("Hiview is already started, exit! \n");
843 exit(1);
844 }
845 FileUtil::SaveStringToFile(pidFile, std::to_string(selfPid));
846 }
847 #else
ExitHiviewIfNeed()848 void HiviewPlatform::ExitHiviewIfNeed()
849 {
850 }
851 #endif
852
GetPluginConfigPath()853 std::string HiviewPlatform::GetPluginConfigPath()
854 {
855 return defaultConfigDir_ + defaultConfigName_;
856 }
857
AppendPluginToPipeline(const std::string & pluginName,const std::string & pipelineName)858 void HiviewPlatform::AppendPluginToPipeline(const std::string& pluginName, const std::string& pipelineName)
859 {
860 auto it = pipelines_.find(pipelineName);
861 if (it == pipelines_.end()) {
862 HIVIEW_LOGW("Fail to find pipeline with name :%{public}s", pipelineName.c_str());
863 return;
864 }
865 auto ptr = GetPluginByName(pluginName);
866 if (ptr == nullptr) {
867 HIVIEW_LOGW("Fail to find plugin with name :%{public}s", pluginName.c_str());
868 return;
869 }
870 it->second->AppendProcessor(ptr);
871 HIVIEW_LOGI("plugin %{public}s add to pipeline %{public}s succeed.", pluginName.c_str(), pipelineName.c_str());
872 }
873
RequestLoadBundle(const std::string & bundleName)874 void HiviewPlatform::RequestLoadBundle(const std::string& bundleName)
875 {
876 if (pluginBundleInfos_.find(bundleName) != pluginBundleInfos_.end()) {
877 HIVIEW_LOGW("Bundle already loaded.");
878 return;
879 }
880
881 std::string configPath = defaultConfigDir_ + bundleName + "_plugin_config";
882 LoadPluginBundle(bundleName, configPath);
883 }
884
RequestUnloadBundle(const std::string & bundleName,uint64_t delay)885 void HiviewPlatform::RequestUnloadBundle(const std::string& bundleName, uint64_t delay)
886 {
887 auto task = [this, bundleName]() {
888 HIVIEW_LOGI("start to unload the bundle %{public}s.", bundleName.c_str());
889 if (pluginBundleInfos_.find(bundleName) != pluginBundleInfos_.end()) {
890 pluginBundleInfos_.erase(bundleName);
891 }
892 };
893 sharedWorkLoop_->AddTimerEvent(nullptr, nullptr, task, delay, false);
894 }
895
InstancePluginByProxy(std::shared_ptr<Plugin> proxy)896 std::shared_ptr<Plugin> HiviewPlatform::InstancePluginByProxy(std::shared_ptr<Plugin> proxy)
897 {
898 if (proxy == nullptr) {
899 return nullptr;
900 }
901
902 auto proxyPtr = std::static_pointer_cast<PluginProxy>(proxy);
903 std::shared_ptr<PluginRegistInfo> registInfo = PluginFactory::GetGlobalPluginInfo(proxyPtr->GetName());
904 if (registInfo == nullptr) {
905 HIVIEW_LOGE("Failed to find registInfo:%{public}s", proxyPtr->GetName().c_str());
906 return nullptr;
907 }
908
909 auto plugin = registInfo->getPluginObject();
910 plugin->SetName(proxyPtr->GetName());
911 plugin->SetHiviewContext(this);
912 plugin->BindWorkLoop(proxyPtr->GetWorkLoop());
913 plugin->OnLoad();
914 auto config = proxyPtr->GetPluginConfig();
915 if (config.isEventSource) {
916 auto sharedSource = std::static_pointer_cast<EventSource>(plugin);
917 for (auto& pipelineName : config.pipelineNameList) {
918 sharedSource->AddPipeline(pipelines_[pipelineName]);
919 }
920 eventSourceList_.push_back(plugin);
921 }
922 return plugin;
923 }
924
GetPluginByName(const std::string & name)925 std::shared_ptr<Plugin> HiviewPlatform::GetPluginByName(const std::string& name)
926 {
927 auto it = pluginMap_.find(name);
928 if (it == pluginMap_.end()) {
929 return nullptr;
930 }
931 return it->second;
932 }
933
GetHiviewProperty(const std::string & key,const std::string & defaultValue)934 std::string HiviewPlatform::GetHiviewProperty(const std::string& key, const std::string& defaultValue)
935 {
936 auto propPair = hiviewProperty_.find(key);
937 if (propPair != hiviewProperty_.end()) {
938 return propPair->second;
939 }
940 return Parameter::GetString(key, defaultValue);
941 }
942
SetHiviewProperty(const std::string & key,const std::string & value,bool forceUpdate)943 bool HiviewPlatform::SetHiviewProperty(const std::string& key, const std::string& value, bool forceUpdate)
944 {
945 auto propPair = hiviewProperty_.find(key);
946 if (forceUpdate || (propPair == hiviewProperty_.end())) {
947 hiviewProperty_[key] = value;
948 return true;
949 }
950 return Parameter::SetProperty(key, value);
951 }
952
CheckUnloadablePlugins()953 void HiviewPlatform::CheckUnloadablePlugins()
954 {
955 for (auto const &pluginKv : pluginMap_) {
956 if (pluginKv.second->GetType() != Plugin::PluginType::PROXY) {
957 continue;
958 }
959 auto ptr = std::static_pointer_cast<PluginProxy>(pluginKv.second);
960 if (ptr == nullptr) {
961 continue;
962 }
963 std::shared_ptr<EventLoop> eventloop = ptr->GetWorkLoop();
964 if (eventloop != nullptr) {
965 auto task = std::bind(&PluginProxy::DestroyInstanceIfNeed, ptr.get(), maxIdleTime_);
966 if (eventloop->AddEvent(nullptr, nullptr, task) != 0) {
967 continue;
968 }
969 HIVIEW_LOGW("AddEvent failed");
970 }
971 ptr->DestroyInstanceIfNeed(maxIdleTime_);
972 }
973 }
974
ScheduleCheckUnloadablePlugins()975 void HiviewPlatform::ScheduleCheckUnloadablePlugins()
976 {
977 auto task = std::bind(&HiviewPlatform::CheckUnloadablePlugins, this);
978 sharedWorkLoop_->AddTimerEvent(nullptr, nullptr, task, checkIdlePeriod_, true);
979 }
980
AddDispatchInfo(std::weak_ptr<Plugin> plugin,const std::unordered_set<uint8_t> & types,const std::unordered_set<std::string> & eventNames,const std::unordered_set<std::string> & tags,const std::unordered_map<std::string,DomainRule> & domainRulesMap)981 void HiviewPlatform::AddDispatchInfo(std::weak_ptr<Plugin> plugin, const std::unordered_set<uint8_t>& types,
982 const std::unordered_set<std::string>& eventNames, const std::unordered_set<std::string>& tags,
983 const std::unordered_map<std::string, DomainRule>& domainRulesMap)
984 {
985 auto ptr = plugin.lock();
986 if (ptr == nullptr) {
987 return;
988 }
989 auto name = ptr->GetName();
990 auto itDispatchInfo = dispatchers_.find(name);
991 std::shared_ptr<DispatchInfo> data = nullptr;
992 if (itDispatchInfo == dispatchers_.end()) {
993 auto tmp = std::make_shared<DispatchInfo>();
994 tmp->plugin_ = plugin;
995 dispatchers_[name] = tmp;
996 data = dispatchers_[name];
997 } else {
998 data = itDispatchInfo->second;
999 }
1000 if (!types.empty()) {
1001 data->typesInfo_.insert(types.begin(), types.end());
1002 }
1003 if (!tags.empty()) {
1004 data->tagsInfo_.insert(tags.begin(), tags.end());
1005 }
1006 if (!eventNames.empty()) {
1007 data->eventsInfo_.insert(eventNames.begin(), eventNames.end());
1008 }
1009 if (!domainRulesMap.empty()) {
1010 data->domainsInfo_.insert(domainRulesMap.begin(), domainRulesMap.end());
1011 }
1012 }
1013
AddListenerInfo(uint32_t type,const std::string & name,const std::set<std::string> & eventNames,const std::map<std::string,DomainRule> & domainRulesMap)1014 void HiviewPlatform::AddListenerInfo(uint32_t type, const std::string& name, const std::set<std::string>& eventNames,
1015 const std::map<std::string, DomainRule>& domainRulesMap)
1016 {
1017 auto itListenerInfo = listeners_.find(name);
1018 std::shared_ptr<ListenerInfo> data = nullptr;
1019 if (itListenerInfo == listeners_.end()) {
1020 auto tmp = std::make_shared<ListenerInfo>();
1021 listeners_[name] = tmp;
1022 data = listeners_[name];
1023 } else {
1024 data = itListenerInfo->second;
1025 }
1026 if (!eventNames.empty()) {
1027 auto it = data->eventsInfo_.find(type);
1028 if (it != data->eventsInfo_.end()) {
1029 it->second.insert(eventNames.begin(), eventNames.end());
1030 } else {
1031 data->eventsInfo_[type] = eventNames;
1032 }
1033 }
1034 if (!domainRulesMap.empty()) {
1035 auto it = data->domainsInfo_.find(type);
1036 if (it != data->domainsInfo_.end()) {
1037 it->second.insert(domainRulesMap.begin(), domainRulesMap.end());
1038 } else {
1039 data->domainsInfo_[type] = domainRulesMap;
1040 }
1041 }
1042 }
1043
AddListenerInfo(uint32_t type,const std::string & name)1044 void HiviewPlatform::AddListenerInfo(uint32_t type, const std::string& name)
1045 {
1046 auto itListenerInfo = listeners_.find(name);
1047 std::shared_ptr<ListenerInfo> data = nullptr;
1048 if (itListenerInfo == listeners_.end()) {
1049 auto tmp = std::make_shared<ListenerInfo>();
1050 listeners_[name] = tmp;
1051 data = listeners_[name];
1052 } else {
1053 data = itListenerInfo->second;
1054 }
1055 data->messageTypes_.push_back(type);
1056 }
1057
GetListenerInfo(uint32_t type,const std::string & eventName,const std::string & domain)1058 std::vector<std::weak_ptr<EventListener>> HiviewPlatform::GetListenerInfo(uint32_t type,
1059 const std::string& eventName, const std::string& domain)
1060 {
1061 std::vector<std::weak_ptr<EventListener>> ret;
1062 for (auto& pairListener : listeners_) {
1063 auto listenerInfo = pairListener.second;
1064 if (listenerInfo->Match(type, eventName, domain)) {
1065 ret.push_back(listenerInfo->listener_);
1066 }
1067 }
1068 return ret;
1069 }
1070
GetDisPatcherInfo(uint32_t type,const std::string & eventName,const std::string & tag,const std::string & domain)1071 std::vector<std::weak_ptr<Plugin>> HiviewPlatform::GetDisPatcherInfo(uint32_t type,
1072 const std::string& eventName, const std::string& tag, const std::string& domain)
1073 {
1074 std::vector<std::weak_ptr<Plugin>> ret;
1075 for (auto& pairDispatcher : dispatchers_) {
1076 auto dispatcherInfo = pairDispatcher.second;
1077 if (dispatcherInfo->Match(type, eventName, tag, domain)) {
1078 ret.push_back(dispatcherInfo->plugin_);
1079 }
1080 }
1081 return ret;
1082 }
1083 } // namespace HiviewDFX
1084 } // namespace OHOS
1085