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