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 48namespace OHOS { 49namespace HiviewDFX { 50namespace { 51constexpr uint32_t AID_SYSTEM = 1000; 52static const char VERSION[] = "1.0.0.0"; 53static const char SEPARATOR_VERSION[] = " "; 54static const char RECORDER_VERSION[] = "01.00"; 55static const char PLUGIN_CONFIG_NAME[] = "plugin_config"; 56static const char HIVIEW_PID_FILE_NAME[] = "hiview.pid"; 57static const char DEFAULT_CONFIG_DIR[] = "/system/etc/hiview/"; 58static const char PIPELINE_RULE_CONFIG_DIR[] = "/system/etc/hiview/dispatch_rule/"; 59static const char DISPATCH_RULE_CONFIG_DIR[] = "/system/etc/hiview/listener_rule/"; 60static const char DEFAULT_WORK_DIR[] = "/data/log/hiview/"; 61static const char DEFAULT_COMMERCIAL_WORK_DIR[] = "/log/LogService/"; 62static const char DEFAULT_PERSIST_DIR[] = "/log/hiview/"; 63static const char LIB_SEARCH_DIR[] = "/system/lib/"; 64static const char LIB64_SEARCH_DIR[] = "/system/lib64/"; 65} 66DEFINE_LOG_TAG("HiView-HiviewPlatform"); 67HiviewPlatform::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 81HiviewPlatform::~HiviewPlatform() 82{ 83 if (unorderQueue_ != nullptr) { 84 unorderQueue_->Stop(); 85 } 86 87 if (sharedWorkLoop_ != nullptr) { 88 sharedWorkLoop_->StopLoop(); 89 } 90 HiviewGlobal::ReleaseInstance(); 91} 92 93void HiviewPlatform::SetMaxProxyIdleTime(time_t idleTime) 94{ 95 maxIdleTime_ = idleTime; 96} 97 98void HiviewPlatform::SetCheckProxyIdlePeriod(time_t period) 99{ 100 checkIdlePeriod_ = period; 101} 102 103bool 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 153void 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 175void 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 191void 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 219void HiviewPlatform::UpdateBetaConfigIfNeed() 220{ 221} 222 223void 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 268std::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 290std::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 302void 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 326void 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 340void 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 356DynamicModule 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 369std::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 396void 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 451void 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 485void 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 536void 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 544void 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 560std::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 575void 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 587void 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 603void HiviewPlatform::StartLoop() 604{ 605 // empty implementation 606} 607 608void 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 621std::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 634void 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 650void 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 668bool 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 695void 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 721std::shared_ptr<EventLoop> HiviewPlatform::GetSharedWorkLoop() 722{ 723 return sharedWorkLoop_; 724} 725 726bool HiviewPlatform::IsReady() 727{ 728 return isReady_; 729} 730 731void 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 745void 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 785std::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 800void 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 811void 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 820void 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 848void HiviewPlatform::ExitHiviewIfNeed() 849{ 850} 851#endif 852 853std::string HiviewPlatform::GetPluginConfigPath() 854{ 855 return defaultConfigDir_ + defaultConfigName_; 856} 857 858void 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 874void 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 885void 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 896std::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 925std::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 934std::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 943bool 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 953void 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 975void HiviewPlatform::ScheduleCheckUnloadablePlugins() 976{ 977 auto task = std::bind(&HiviewPlatform::CheckUnloadablePlugins, this); 978 sharedWorkLoop_->AddTimerEvent(nullptr, nullptr, task, checkIdlePeriod_, true); 979} 980 981void 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 1014void 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 1044void 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 1058std::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 1071std::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