1/*
2 * Copyright (c) 2023-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 "module_loader.h"
16
17#include <dlfcn.h>
18
19#include "app_event_processor_proxy.h"
20#include "file_util.h"
21#include "hiappevent_base.h"
22#include "hilog/log.h"
23
24#undef LOG_DOMAIN
25#define LOG_DOMAIN 0xD002D07
26
27#undef LOG_TAG
28#define LOG_TAG "ModuleLoader"
29
30namespace OHOS {
31namespace HiviewDFX {
32namespace HiAppEvent {
33namespace {
34std::string GetModulePath(const std::string& moduleName)
35{
36    const std::string searchDirs[] = {
37        "/system/lib/platformsdk/", "/system/lib64/platformsdk/", "/system/lib/", "/system/lib64/"
38    };
39    std::string modulePath;
40    std::string libName = "lib" + moduleName + ".z.so";
41    for (auto& searchDir : searchDirs) {
42        std::string tempModulePath = searchDir + libName;
43        if (FileUtil::IsFileExists(tempModulePath)) {
44            modulePath = tempModulePath;
45            break;
46        }
47    }
48    return modulePath;
49}
50}
51std::mutex ModuleLoader::moduleMutex_;
52std::mutex ModuleLoader::processorMutex_;
53
54ModuleLoader::~ModuleLoader()
55{
56    processors_.clear();
57
58    for (auto it = modules_.begin(); it != modules_.end(); ++it) {
59        dlclose(it->second);
60        HILOG_INFO(LOG_CORE, "succ to unload module=%{public}s", it->first.c_str());
61    }
62    modules_.clear();
63}
64
65int ModuleLoader::Load(const std::string& moduleName)
66{
67    std::lock_guard<std::mutex> lock(moduleMutex_);
68    if (modules_.find(moduleName) != modules_.end()) {
69        HILOG_DEBUG(LOG_CORE, "the module=%{public}s already exists", moduleName.c_str());
70        return 0;
71    }
72
73    std::string modulePath = GetModulePath(moduleName);
74    if (modulePath.empty()) {
75        HILOG_WARN(LOG_CORE, "the module=%{public}s does not exist.", moduleName.c_str());
76        return -1;
77    }
78    void* handler = nullptr;
79    if (handler = dlopen(modulePath.c_str(), RTLD_GLOBAL); handler == nullptr) {
80        HILOG_ERROR(LOG_CORE, "failed to load module=%{public}s, error=%{public}s.", modulePath.c_str(), dlerror());
81        return -1;
82    }
83    HILOG_INFO(LOG_CORE, "succ to load module=%{public}s.", modulePath.c_str());
84    modules_[moduleName] = handler;
85    return 0;
86}
87
88int ModuleLoader::Unload(const std::string& moduleName)
89{
90    std::lock_guard<std::mutex> lock(moduleMutex_);
91    if (modules_.find(moduleName) == modules_.end()) {
92        HILOG_WARN(LOG_CORE, "the module=%{public}s does not exists", moduleName.c_str());
93        return -1;
94    }
95    dlclose(modules_[moduleName]);
96    modules_.erase(moduleName);
97    HILOG_INFO(LOG_CORE, "succ to unload module=%{public}s", moduleName.c_str());
98    return 0;
99}
100
101int ModuleLoader::RegisterProcessor(const std::string& name, std::shared_ptr<AppEventProcessor> processor)
102{
103    if (name.empty() || processor == nullptr) {
104        HILOG_WARN(LOG_CORE, "the name or processor is invalid");
105        return -1;
106    }
107    std::lock_guard<std::mutex> lock(processorMutex_);
108    if (processors_.find(name) != processors_.end()) {
109        HILOG_WARN(LOG_CORE, "the processor already exists");
110        return -1;
111    }
112    processors_[name] = processor;
113    return 0;
114}
115
116int ModuleLoader::UnregisterProcessor(const std::string& name)
117{
118    std::lock_guard<std::mutex> lock(processorMutex_);
119    if (processors_.find(name) == processors_.end()) {
120        HILOG_WARN(LOG_CORE, "the name is invalid");
121        return -1;
122    }
123    processors_.erase(name);
124    return 0;
125}
126
127std::shared_ptr<AppEventObserver> ModuleLoader::CreateProcessorProxy(const std::string& name)
128{
129    std::lock_guard<std::mutex> lock(processorMutex_);
130    if (processors_.find(name) == processors_.end()) {
131        HILOG_WARN(LOG_CORE, "the name is invalid");
132        return nullptr;
133    }
134    return std::make_shared<AppEventProcessorProxy>(name, processors_[name]);
135}
136} // namespace HiAppEvent
137} // namespace HiviewDFX
138} // namespace OHOS
139