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