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