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