1/*
2 * Copyright (c) 2022-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
16#include "plugin_manager.h"
17
18#include <cstring>
19#include <dirent.h>
20#include <dlfcn.h>
21#include <iostream>
22#include <mutex>
23#include <string_ex.h>
24#include <unistd.h>
25
26#include "edm_ipc_interface_code.h"
27#include "edm_log.h"
28#include "func_code_utils.h"
29#include "permission_manager.h"
30
31namespace OHOS {
32namespace EDM {
33std::shared_ptr<PluginManager> PluginManager::instance_;
34std::mutex PluginManager::mutexLock_;
35
36PluginManager::PluginManager()
37{
38    EDMLOGD("PluginManager::PluginManager.");
39}
40
41PluginManager::~PluginManager()
42{
43    EDMLOGD("PluginManager::~PluginManager.");
44    pluginsCode_.clear();
45    pluginsName_.clear();
46    for (auto handle : pluginHandles_) {
47        dlclose(handle);
48    }
49    pluginHandles_.clear();
50}
51
52std::shared_ptr<PluginManager> PluginManager::GetInstance()
53{
54    if (instance_ == nullptr) {
55        std::lock_guard<std::mutex> autoLock(mutexLock_);
56        if (instance_ == nullptr) {
57            instance_.reset(new (std::nothrow) PluginManager());
58        }
59    }
60
61    IPluginManager::pluginManagerInstance_ = instance_.get();
62    return instance_;
63}
64
65std::shared_ptr<IPlugin> PluginManager::GetPluginByFuncCode(std::uint32_t funcCode)
66{
67    FuncCodeUtils::PrintFuncCode(funcCode);
68    FuncFlag flag = FuncCodeUtils::GetSystemFlag(funcCode);
69    if (flag == FuncFlag::POLICY_FLAG) {
70        std::uint32_t code = FuncCodeUtils::GetPolicyCode(funcCode);
71        EDMLOGD("PluginManager::code %{public}u", code);
72        auto it = pluginsCode_.find(code);
73        if (it != pluginsCode_.end()) {
74            return it->second;
75        }
76    }
77    EDMLOGD("GetPluginByFuncCode::return nullptr");
78    return nullptr;
79}
80
81std::shared_ptr<IPlugin> PluginManager::GetPluginByPolicyName(const std::string &policyName)
82{
83    auto it = pluginsName_.find(policyName);
84    if (it != pluginsName_.end()) {
85        return it->second;
86    }
87    return nullptr;
88}
89
90std::shared_ptr<IPlugin> PluginManager::GetPluginByCode(std::uint32_t code)
91{
92    EDMLOGD("PluginManager::code %{public}u", code);
93    auto it = pluginsCode_.find(code);
94    if (it != pluginsCode_.end()) {
95        return it->second;
96    }
97    EDMLOGD("GetPluginByCode::return nullptr");
98    return nullptr;
99}
100
101std::shared_ptr<IPluginExecuteStrategy> PluginManager::CreateExecuteStrategy(ExecuteStrategy strategy)
102{
103    if (strategy == ExecuteStrategy::ENHANCE) {
104        return enhanceStrategy_;
105    }
106    if (strategy == ExecuteStrategy::REPLACE) {
107        return replaceStrategy_;
108    }
109    return singleStrategy_;
110}
111
112bool PluginManager::AddPlugin(std::shared_ptr<IPlugin> plugin)
113{
114    if (plugin == nullptr) {
115        return false;
116    }
117    EDMLOGD("AddPlugin %{public}d", plugin->GetCode());
118    IPlugin::PolicyPermissionConfig setConfig = plugin->GetAllPermission(FuncOperateType::SET);
119    IPlugin::PolicyPermissionConfig getConfig = plugin->GetAllPermission(FuncOperateType::GET);
120    IPlugin::PermissionType setType = plugin->GetPermissionType(FuncOperateType::SET);
121    IPlugin::PermissionType getType = plugin->GetPermissionType(FuncOperateType::GET);
122    ErrCode result = PermissionManager::GetInstance()->AddPermission(setConfig.permission, setType);
123    if (result == ERR_OK && getConfig.permission != setConfig.permission) {
124        result = PermissionManager::GetInstance()->AddPermission(getConfig.permission, getType);
125    }
126    if (result == ERR_OK) {
127        for (auto &item : setConfig.tagPermissions) {
128            if (PermissionManager::GetInstance()->AddPermission(item.second, setType) != ERR_OK) {
129                return false;
130            }
131        }
132        for (auto &item : getConfig.tagPermissions) {
133            if (PermissionManager::GetInstance()->AddPermission(item.second, getType) != ERR_OK) {
134                return false;
135            }
136        }
137        pluginsCode_.insert(std::make_pair(plugin->GetCode(), plugin));
138        pluginsName_.insert(std::make_pair(plugin->GetPolicyName(), plugin));
139        if (extensionPluginMap_.count(plugin->GetCode()) > 0) {
140            EDMLOGD("PluginManager::AddPlugin %{public}d add extension plugin %{public}d", plugin->GetCode(),
141                extensionPluginMap_[plugin->GetCode()]);
142            plugin->SetExtensionPlugin(GetPluginByCode(extensionPluginMap_[plugin->GetCode()]));
143        }
144        if (executeStrategyMap_.count(plugin->GetCode()) > 0) {
145            plugin->SetExecuteStrategy(CreateExecuteStrategy(executeStrategyMap_[plugin->GetCode()]));
146        } else {
147            plugin->SetExecuteStrategy(CreateExecuteStrategy(ExecuteStrategy::SINGLE));
148        }
149        return true;
150    }
151    return false;
152}
153
154bool PluginManager::AddExtensionPlugin(std::shared_ptr<IPlugin> extensionPlugin, uint32_t basicPluginCode,
155    ExecuteStrategy strategy)
156{
157    if (AddPlugin(extensionPlugin)) {
158        auto basicPlugin = GetPluginByCode(basicPluginCode);
159        if (basicPlugin != nullptr) {
160            EDMLOGD("PluginManager::AddExtensionPlugin %{public}d add extension plugin %{public}d", basicPluginCode,
161                extensionPlugin->GetCode());
162            basicPlugin->SetExtensionPlugin(extensionPlugin);
163            basicPlugin->SetExecuteStrategy(CreateExecuteStrategy(strategy));
164        }
165        extensionPlugin->SetPluginType(IPlugin::PluginType::EXTENSION);
166        extensionPluginMap_.insert(std::make_pair(basicPluginCode, extensionPlugin->GetCode()));
167        executeStrategyMap_.insert(std::make_pair(basicPluginCode, strategy));
168        return true;
169    }
170    return false;
171}
172
173void PluginManager::LoadPlugin()
174{
175    std::lock_guard<std::mutex> autoLock(mutexLock_);
176#if defined(_ARM64_) || defined(_X86_64_)
177    std::string pluginDir = "/system/lib64/edm_plugin/";
178#else
179    std::string pluginDir = "/system/lib/edm_plugin/";
180#endif
181    DIR *dir = opendir(pluginDir.c_str());
182    if (dir == nullptr) {
183        EDMLOGE("PluginManager::LoadPlugin open edm_plugin dir fail.");
184        return;
185    }
186    struct dirent *entry;
187    while ((entry = readdir(dir)) != nullptr) {
188        if (entry->d_type == DT_REG && strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
189            LoadPlugin(pluginDir + entry->d_name);
190        }
191    }
192    closedir(dir);
193}
194
195void PluginManager::LoadPlugin(const std::string &pluginPath)
196{
197    void *handle = dlopen(pluginPath.c_str(), RTLD_LAZY);
198    if (!handle) {
199        EDMLOGE("PluginManager::open plugin so fail. %{public}s.", dlerror());
200        return;
201    }
202    pluginHandles_.push_back(handle);
203}
204
205void PluginManager::UnloadPlugin()
206{
207    std::lock_guard<std::mutex> autoLock(mutexLock_);
208    for (auto codeIter = pluginsCode_.begin(); codeIter != pluginsCode_.end();) {
209        if (codeIter->second != nullptr) {
210            codeIter->second->ResetExtensionPlugin();
211        }
212        if (codeIter->second == nullptr || codeIter->first > static_cast<uint32_t>(EdmInterfaceCode::POLICY_CODE_END)) {
213            codeIter = pluginsCode_.erase(codeIter);
214        } else {
215            ++codeIter;
216        }
217    }
218    for (auto nameIter = pluginsName_.begin(); nameIter != pluginsName_.end();) {
219        if (nameIter->second == nullptr ||
220            nameIter->second->GetCode() > static_cast<uint32_t>(EdmInterfaceCode::POLICY_CODE_END)) {
221            nameIter = pluginsName_.erase(nameIter);
222        } else {
223            ++nameIter;
224        }
225    }
226    for (auto handleIter = pluginHandles_.begin(); handleIter != pluginHandles_.end();) {
227        auto handle = *handleIter;
228        if (handle == nullptr || dlclose(handle) == 0) {
229            handleIter = pluginHandles_.erase(handleIter);
230        } else {
231            EDMLOGE("PluginManager::UnloadPlugin close handle failed.");
232            ++handleIter;
233        }
234    }
235    EDMLOGI("PluginManager::UnloadPlugin finish.");
236}
237
238void PluginManager::DumpPlugin()
239{
240    for (auto it = pluginsCode_.begin(); it != pluginsCode_.end(); it++) {
241        std::string setTagPermissions;
242        std::string getTagPermissions;
243        IPlugin::PolicyPermissionConfig setConfig = it->second->GetAllPermission(FuncOperateType::SET);
244        IPlugin::PolicyPermissionConfig getConfig = it->second->GetAllPermission(FuncOperateType::GET);
245        for (auto &item : setConfig.tagPermissions) {
246            setTagPermissions.append(item.second);
247        }
248        for (auto &item : getConfig.tagPermissions) {
249            getTagPermissions.append(item.second);
250        }
251        EDMLOGD("PluginManager::Dump plugins_code.code:%{public}u,name:%{public}s,get permission:%{public}s, "
252            "set permission:%{public}s,get tagPermissions:%{public}s,set tagPermissions:%{public}s",
253            it->first, it->second->GetPolicyName().c_str(),
254            it->second->GetPermission(FuncOperateType::GET).c_str(),
255            it->second->GetPermission(FuncOperateType::SET).c_str(),
256            getTagPermissions.c_str(), setTagPermissions.c_str());
257    }
258    for (auto it = pluginsName_.begin(); it != pluginsName_.end(); it++) {
259        std::string setTagPermissions;
260        std::string getTagPermissions;
261        IPlugin::PolicyPermissionConfig setConfig = it->second->GetAllPermission(FuncOperateType::SET);
262        IPlugin::PolicyPermissionConfig getConfig = it->second->GetAllPermission(FuncOperateType::GET);
263        for (auto &item : setConfig.tagPermissions) {
264            setTagPermissions.append(item.second);
265        }
266        for (auto &item : getConfig.tagPermissions) {
267            getTagPermissions.append(item.second);
268        }
269        EDMLOGD("PluginManager::Dump plugins_name.name:%{public}s,code:%{public}u,get permission type:%{public}s, "
270            "set permission type:%{public}s,get tagPermissions:%{public}s,set tagPermissions:%{public}s",
271            it->first.c_str(), it->second->GetCode(),
272            it->second->GetPermission(FuncOperateType::GET).c_str(),
273            it->second->GetPermission(FuncOperateType::SET).c_str(),
274            getTagPermissions.c_str(), setTagPermissions.c_str());
275    }
276}
277} // namespace EDM
278} // namespace OHOS
279