1 /*
2 * Copyright (C) 2021 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_mgr.h"
17 #include <fstream>
18 #include <sstream>
19 #include "directory_ex.h"
20 #include "hilog/log.h"
21 #include "json.hpp"
22 #include "json_helper.h"
23 #include "log_tags.h"
24 #include "platform_adp.h"
25 #include "plugin.h"
26 #include "plugin_metadata.h"
27
28 namespace OHOS {
29 namespace MultimediaPlugin {
30 using nlohmann::json;
31 using std::ifstream;
32 using std::istringstream;
33 using std::size_t;
34 using std::string;
35 using std::vector;
36 using std::weak_ptr;
37 using namespace OHOS::HiviewDFX;
38
39 static constexpr HiLogLabel LABEL = { LOG_CORE, LOG_TAG_DOMAIN_ID_PLUGIN, "PluginMgr" };
40 PlatformAdp &PluginMgr::platformAdp_ = DelayedRefSingleton<PlatformAdp>::GetInstance();
41
Register(const vector<string> & canonicalPaths)42 uint32_t PluginMgr::Register(const vector<string> &canonicalPaths)
43 {
44 if (canonicalPaths.empty()) {
45 const vector<string> &metadata = OHOS::MultimediaPlugin::META_DATA;
46 for (size_t i = 0; i < metadata.size(); i++) {
47 uint32_t errorCode = RegisterPlugin(metadata[i]);
48 if (errorCode != SUCCESS) {
49 return errorCode;
50 }
51 }
52 return SUCCESS;
53 }
54
55 bool pathTraversed = false;
56 uint32_t errorCode = SUCCESS;
57 for (const string &path : canonicalPaths) {
58 uint32_t result = TraverseFiles(path);
59 if (result == SUCCESS) {
60 pathTraversed = true;
61 } else {
62 // no target is not a critical error type, giving priority to more serious errors.
63 if ((errorCode == SUCCESS) || (errorCode == ERR_NO_TARGET)) {
64 errorCode = result;
65 }
66 }
67 }
68
69 if (!pathTraversed) {
70 return errorCode;
71 }
72
73 return SUCCESS;
74 }
75
76 // ------------------------------- private method -------------------------------
PluginMgr()77 PluginMgr::PluginMgr()
78 {}
79
~PluginMgr()80 PluginMgr::~PluginMgr()
81 {}
82
TraverseFiles(const string & canonicalPath)83 uint32_t PluginMgr::TraverseFiles(const string &canonicalPath)
84 {
85 bool noTarget = true;
86 vector<string> strFiles;
87 GetDirFiles(canonicalPath, strFiles);
88 if (strFiles.empty()) {
89 HiLog::Error(LABEL, "failed to get dir files.");
90 return ERR_GENERAL;
91 }
92
93 string libraryPath;
94 for (const auto &file : strFiles) {
95 if (!CheckPluginMetaFile(file, libraryPath)) {
96 continue;
97 }
98 noTarget = false;
99 RegisterPlugin(file, std::move(libraryPath));
100 }
101
102 if (noTarget) {
103 HiLog::Warn(LABEL, "there is no plugin meta file in path.");
104 return ERR_NO_TARGET;
105 }
106
107 return SUCCESS;
108 }
109
CheckPluginMetaFile(const string & candidateFile,string & libraryPath)110 bool PluginMgr::CheckPluginMetaFile(const string &candidateFile, string &libraryPath)
111 {
112 const string meatedataFileSuffix = "pluginmeta";
113
114 #ifdef _WIN32
115 const string libraryFileSuffix = "dll";
116 #elif defined _APPLE
117 const string libraryFileSuffix = "dylib";
118 #else
119 const string libraryFileSuffix = "so";
120 #endif
121
122 string fileExt = ExtractFileExt(candidateFile);
123 if (fileExt != meatedataFileSuffix) {
124 // not a plugin metadata file, quietly skip this item.
125 return false;
126 }
127
128 ifstream metadata(candidateFile);
129 if (!metadata) {
130 HiLog::Error(LABEL, "failed to open metadata file.");
131 return false;
132 }
133
134 json root;
135 metadata >> root;
136 if (JsonHelper::GetStringValue(root, "libraryPath", libraryPath) != SUCCESS) {
137 HiLog::Error(LABEL, "read libraryPath failed.");
138 return false;
139 }
140
141 #if defined(_WIN32) || defined(_APPLE)
142 libraryPath = TransformFileName(libraryPath);
143 #endif
144
145 fileExt = ExtractFileExt(libraryPath);
146 if (fileExt != libraryFileSuffix) {
147 HiLog::Error(LABEL, "invalid library suffix.");
148 return false;
149 }
150
151 #if !defined(_WIN32) && !defined(_APPLE)
152 const string dirSeparator = "/";
153 if (libraryPath.substr(0, 1) != dirSeparator) {
154 // relative path to absolute path.
155 // just keep original library name
156 return true;
157 }
158 #endif
159
160 string realPath;
161 if (!PathToRealPath(libraryPath, realPath)) {
162 HiLog::Error(LABEL, "library path to real path error.");
163 return false;
164 }
165
166 libraryPath = std::move(realPath);
167 return true;
168 }
169
RegisterPlugin(const string & metadataPath,string && libraryPath)170 uint32_t PluginMgr::RegisterPlugin(const string &metadataPath, string &&libraryPath)
171 {
172 auto iter = plugins_.find(&libraryPath);
173 if (iter != plugins_.end()) {
174 // already registered before, just skip it.
175 HiLog::Debug(LABEL, "the libraryPath has already been registered before.");
176 return ERR_GENERAL;
177 }
178
179 ifstream metadata(metadataPath);
180 if (!metadata) {
181 HiLog::Error(LABEL, "failed to open metadata file.");
182 return ERR_GENERAL;
183 }
184
185 auto plugin = std::make_shared<Plugin>();
186 if (plugin == nullptr) {
187 HiLog::Error(LABEL, "failed to create Plugin.");
188 return ERR_INTERNAL;
189 }
190
191 weak_ptr<Plugin> weakPtr = plugin;
192 auto regRet = plugin->Register(metadata, std::move(libraryPath), weakPtr);
193 if (regRet != SUCCESS) {
194 HiLog::Error(LABEL, "failed to register plugin,ERRNO: %{public}u.", regRet);
195 return regRet;
196 }
197
198 const std::string &key = plugin->GetLibraryPath();
199 if (key.empty()) {
200 HiLog::Error(LABEL, "get empty libraryPath.");
201 return ERR_INTERNAL;
202 }
203
204 auto insertRet = plugins_.insert(PluginMap::value_type(&key, std::move(plugin)));
205 if (!insertRet.second) {
206 HiLog::Error(LABEL, "failed to insert Plugin");
207 return ERR_INTERNAL;
208 }
209
210 return SUCCESS;
211 }
212
RegisterPlugin(const string & metadataJson)213 uint32_t PluginMgr::RegisterPlugin(const string &metadataJson)
214 {
215 string libraryPath;
216 json root = nlohmann::json::parse(metadataJson);
217 if (JsonHelper::GetStringValue(root, "libraryPath", libraryPath) != SUCCESS) {
218 HiLog::Error(LABEL, "read libraryPath failed.");
219 return false;
220 }
221
222 auto iter = plugins_.find(&libraryPath);
223 if (iter != plugins_.end()) {
224 // already registered before, just skip it.
225 HiLog::Debug(LABEL, "the libraryPath has already been registered before.");
226 return ERR_GENERAL;
227 }
228
229 istringstream metadata(metadataJson);
230 if (!metadata) {
231 HiLog::Error(LABEL, "failed to read metadata.");
232 return ERR_GENERAL;
233 }
234
235 auto crossPlugin = std::make_shared<Plugin>();
236 weak_ptr<Plugin> weakPtr = crossPlugin;
237 auto regRet = crossPlugin->Register(metadata, std::move(libraryPath), weakPtr);
238 if (regRet != SUCCESS) {
239 HiLog::Error(LABEL, "failed to register plugin,ERRNO: %{public}u.", regRet);
240 return regRet;
241 }
242
243 const std::string &key = crossPlugin->GetLibraryPath();
244 if (key.empty()) {
245 HiLog::Error(LABEL, "get empty libraryPath.");
246 return ERR_INTERNAL;
247 }
248
249 auto insertRet = plugins_.insert(PluginMap::value_type(&key, std::move(crossPlugin)));
250 if (!insertRet.second) {
251 HiLog::Error(LABEL, "failed to insert Plugin");
252 return ERR_INTERNAL;
253 }
254
255 return SUCCESS;
256 }
257 } // namespace MultimediaPlugin
258 } // namespace OHOS
259