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.h"
17 #include <utility>
18 #include "image_log.h"
19 #include "impl_class_mgr.h"
20 #include "json.hpp"
21 #include "json_helper.h"
22 #include "platform_adp.h"
23 #include "singleton.h"
24 #ifdef _WIN32
25 #include <windows.h>
26 HMODULE hDll = NULL;
27 #endif
28
29 #undef LOG_DOMAIN
30 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
31
32 #undef LOG_TAG
33 #define LOG_TAG "Plugin"
34
35 namespace OHOS {
36 namespace MultimediaPlugin {
37 using nlohmann::json;
38 using std::istream;
39 using std::istringstream;
40 using std::recursive_mutex;
41 using std::size_t;
42 using std::string;
43 using std::weak_ptr;
44
45 enum class VersionParseStep : int32_t { STEP_MAJOR = 0, STEP_MINOR, STEP_MICRO, STEP_NANO, STEP_FINISHED };
46
47 struct VersionNum {
48 uint16_t major = 0;
49 uint16_t minor = 0;
50 uint16_t micro = 0;
51 uint16_t nano = 0;
52 };
53
Plugin()54 Plugin::Plugin()
55 : platformAdp_(DelayedRefSingleton<PlatformAdp>::GetInstance()),
56 implClassMgr_(DelayedRefSingleton<ImplClassMgr>::GetInstance()) {}
57
~Plugin()58 Plugin::~Plugin()
59 {
60 std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
61 if (refNum_ != 0) {
62 // this situation does not happen in design.
63 // the process context can guarantee that this will not happen.
64 // the judgment statement here is for protection and positioning purposes only.
65 IMAGE_LOGE("release plugin: refNum: %{public}u.", refNum_);
66 }
67
68 implClassMgr_.DeleteClass(plugin_);
69 FreeLibrary();
70 }
71
Register(istream & metadata,string && libraryPath,weak_ptr<Plugin> & plugin)72 uint32_t Plugin::Register(istream &metadata, string &&libraryPath, weak_ptr<Plugin> &plugin)
73 {
74 std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
75 if (state_ != PluginState::PLUGIN_STATE_UNREGISTER) {
76 IMAGE_LOGI("repeat registration.");
77 return ERR_INTERNAL;
78 }
79
80 auto ret = RegisterMetadata(metadata, plugin);
81 if (ret != SUCCESS) {
82 IMAGE_LOGE("failed to register metadata, ERRNO: %{public}u.", ret);
83 return ret;
84 }
85
86 libraryPath_ = std::move(libraryPath);
87 plugin_ = plugin;
88 state_ = PluginState::PLUGIN_STATE_REGISTERED;
89 return SUCCESS;
90 }
91
CfiStartFunc_(PluginStartFunc startFunc_)92 bool CfiStartFunc_(PluginStartFunc startFunc_) __attribute__((no_sanitize("cfi")))
93 {
94 return startFunc_();
95 }
96
Ref()97 uint32_t Plugin::Ref()
98 {
99 // once the client make a ref, it can use the plugin at any time,
100 // so we do the necessary preparations here.
101 std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
102 if (state_ == PluginState::PLUGIN_STATE_REGISTERED) {
103 if (ResolveLibrary() != SUCCESS) {
104 guard.unlock();
105 IMAGE_LOGE("failed to resolve library.");
106 return ERR_GENERAL;
107 }
108 state_ = PluginState::PLUGIN_STATE_RESOLVED;
109 }
110
111 if (state_ == PluginState::PLUGIN_STATE_RESOLVED) {
112 // maybe asynchronous, or for reduce the locking time
113 state_ = PluginState::PLUGIN_STATE_STARTING;
114 if (!CfiStartFunc_(startFunc_)) {
115 IMAGE_LOGE("failed to start plugin.");
116 FreeLibrary();
117 state_ = PluginState::PLUGIN_STATE_REGISTERED;
118 return ERR_GENERAL;
119 }
120 state_ = PluginState::PLUGIN_STATE_ACTIVE;
121 }
122
123 if (state_ != PluginState::PLUGIN_STATE_ACTIVE) {
124 IMAGE_LOGE("plugin ref: state error, state: %{public}d.", state_);
125 return ERR_GENERAL;
126 }
127
128 ++refNum_;
129 IMAGE_LOGD("plugin refNum: %{public}d.", refNum_);
130 return SUCCESS;
131 }
132
DeRef()133 void Plugin::DeRef()
134 {
135 std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
136 if (refNum_ == 0) {
137 // this situation does not happen in design.
138 // the process context can guarantee that this will not happen.
139 // the judgment statement here is for protection and positioning purposes only.
140 guard.unlock();
141 IMAGE_LOGE("DeRef while RefNum is zero.");
142 return;
143 }
144
145 --refNum_;
146 IMAGE_LOGD("plugin refNum: %{public}d.", refNum_);
147 }
148
Block()149 void Plugin::Block()
150 {
151 // used to protect against business interruptions during plugin upgrades.
152 // after the plugin is upgraded, if the original .so is being used,
153 // it cannot be released immediately and should be locked,
154 // and the subsequent requests are migrated to the new .so.
155 std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
156 blocked_ = true;
157 }
158
Unblock()159 void Plugin::Unblock()
160 {
161 std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
162 blocked_ = false;
163 }
164
GetCreateFunc()165 PluginCreateFunc Plugin::GetCreateFunc()
166 {
167 std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
168 if ((state_ != PluginState::PLUGIN_STATE_ACTIVE) || (refNum_ == 0)) {
169 // In this case, we can't guarantee that the pointer is lasting valid.
170 IMAGE_LOGE("failed to get create func, State: %{public}d, RefNum: %{public}u.", state_, refNum_);
171 return nullptr;
172 }
173
174 return createFunc_;
175 }
176
GetLibraryPath() const177 const string &Plugin::GetLibraryPath() const
178 {
179 return libraryPath_;
180 }
181
GetPackageName() const182 const string &Plugin::GetPackageName() const
183 {
184 return packageName_;
185 }
186
187 // ------------------------------- private method -------------------------------
ResolveLibrary()188 uint32_t Plugin::ResolveLibrary()
189 {
190 std::string pluginStartSymbol = "PluginExternalStart";
191 std::string pluginStopSymbol = "PluginExternalStop";
192 std::string pluginCreateSymbol = "PluginExternalCreate";
193
194 #ifdef _WIN32
195 hDll = platformAdp_.AdpLoadLibrary(libraryPath_);
196 if (hDll == NULL) {
197 IMAGE_LOGE("failed to load library.");
198 return ERR_GENERAL;
199 }
200
201 startFunc_ = (PluginStartFunc)platformAdp_.AdpGetSymAddress(hDll, pluginStartSymbol);
202 stopFunc_ = (PluginStopFunc)platformAdp_.AdpGetSymAddress(hDll, pluginStopSymbol);
203 createFunc_ = (PluginCreateFunc)platformAdp_.AdpGetSymAddress(hDll, pluginCreateSymbol);
204 if (startFunc_ == NULL || stopFunc_ == NULL || createFunc_ == NULL) {
205 IMAGE_LOGE("failed to get export symbol for the plugin.");
206 FreeLibrary();
207 return ERR_GENERAL;
208 }
209
210 return SUCCESS;
211 #elif defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
212 startFunc_ = PluginExternalStart;
213 stopFunc_ = PluginExternalStop;
214 createFunc_ = PluginExternalCreate;
215 return SUCCESS;
216 #else
217 IMAGE_LOGD("ResolveLibrary start loading library path %{public}s.", libraryPath_.c_str());
218 handle_ = platformAdp_.LoadLibrary(libraryPath_);
219 if (handle_ == nullptr) {
220 IMAGE_LOGE("failed to load library.");
221 return ERR_GENERAL;
222 }
223
224 startFunc_ = (PluginStartFunc)platformAdp_.GetSymAddress(handle_, pluginStartSymbol);
225 stopFunc_ = (PluginStopFunc)platformAdp_.GetSymAddress(handle_, pluginStopSymbol);
226 createFunc_ = (PluginCreateFunc)platformAdp_.GetSymAddress(handle_, pluginCreateSymbol);
227 if (startFunc_ == nullptr || stopFunc_ == nullptr || createFunc_ == nullptr) {
228 IMAGE_LOGE("failed to get export symbol for the plugin.");
229 FreeLibrary();
230 return ERR_GENERAL;
231 }
232
233 return SUCCESS;
234 #endif
235 }
236
FreeLibrary()237 void Plugin::FreeLibrary()
238 {
239 #ifdef _WIN32
240 if (state_ == PluginState::PLUGIN_STATE_STARTING || state_ == PluginState::PLUGIN_STATE_ACTIVE) {
241 if (stopFunc_ != NULL) {
242 stopFunc_();
243 }
244 }
245 if (handle_ == NULL) {
246 return;
247 }
248 platformAdp_.AdpFreeLibrary(hDll);
249 hDll = NULL;
250 startFunc_ = NULL;
251 stopFunc_ = NULL;
252 createFunc_ = NULL;
253 #elif defined(ANDROID_PLATFORM) || defined(IOS_PLATFORM)
254 startFunc_ = nullptr;
255 stopFunc_ = nullptr;
256 createFunc_ = nullptr;
257 #else
258 if (state_ == PluginState::PLUGIN_STATE_STARTING || state_ == PluginState::PLUGIN_STATE_ACTIVE) {
259 if (stopFunc_ != nullptr) {
260 stopFunc_();
261 }
262 }
263
264 if (handle_ == nullptr) {
265 return;
266 }
267
268 platformAdp_.FreeLibrary(handle_);
269 handle_ = nullptr;
270 startFunc_ = nullptr;
271 stopFunc_ = nullptr;
272 createFunc_ = nullptr;
273 #endif
274 }
275
RegisterMetadata(istream & metadata,weak_ptr<Plugin> & plugin)276 uint32_t Plugin::RegisterMetadata(istream &metadata, weak_ptr<Plugin> &plugin)
277 {
278 json root = nlohmann::json::parse(metadata, nullptr, false); // no callback, no exceptions
279 if (root.is_discarded()) {
280 IMAGE_LOGE("RegisterMetadata parse json failed.");
281 return ERR_INVALID_PARAMETER;
282 }
283 if (JsonHelper::GetStringValue(root, "packageName", packageName_) != SUCCESS) {
284 IMAGE_LOGE("read packageName failed.");
285 return ERR_INVALID_PARAMETER;
286 }
287
288 string targetVersion;
289 if (JsonHelper::GetStringValue(root, "targetVersion", targetVersion) != SUCCESS) {
290 IMAGE_LOGE("read targetVersion failed.");
291 return ERR_INVALID_PARAMETER;
292 }
293 uint32_t ret = CheckTargetVersion(targetVersion);
294 if (ret != SUCCESS) {
295 // target version is not compatible
296 IMAGE_LOGE("check targetVersion failed, Version: %{public}s, ERRNO: %{public}u.", targetVersion.c_str(), ret);
297 return ret;
298 }
299
300 if (JsonHelper::GetStringValue(root, "version", version_) != SUCCESS) {
301 IMAGE_LOGE("read version failed.");
302 return ERR_INVALID_PARAMETER;
303 }
304 VersionNum versionNum;
305 ret = AnalyzeVersion(version_, versionNum);
306 if (ret != SUCCESS) {
307 IMAGE_LOGE("check version failed, Version: %{public}s, ERRNO: %{public}u.", version_.c_str(), ret);
308 return ret;
309 }
310
311 size_t classNum;
312 if (JsonHelper::GetArraySize(root, "classes", classNum) != SUCCESS) {
313 IMAGE_LOGE("get array size of classes failed.");
314 return ERR_INVALID_PARAMETER;
315 }
316 IMAGE_LOGD("parse class num: %{public}zu.", classNum);
317 for (size_t i = 0; i < classNum; i++) {
318 const json &classInfo = root["classes"][i];
319 if (implClassMgr_.AddClass(plugin, classInfo) != SUCCESS) {
320 IMAGE_LOGE("failed to add class, index: %{public}zu.", i);
321 continue;
322 }
323 }
324
325 return SUCCESS;
326 }
327
CheckTargetVersion(const string & targetVersion)328 uint32_t Plugin::CheckTargetVersion(const string &targetVersion)
329 {
330 VersionNum versionNum;
331 auto ret = AnalyzeVersion(targetVersion, versionNum);
332 if (ret != SUCCESS) {
333 IMAGE_LOGE("failed to analyze version, ERRNO: %{public}u.", ret);
334 return ret;
335 }
336
337 return SUCCESS;
338 }
339
AnalyzeVersion(const string & versionInfo,VersionNum & versionNum)340 uint32_t Plugin::AnalyzeVersion(const string &versionInfo, VersionNum &versionNum)
341 {
342 VersionParseStep step = VersionParseStep::STEP_MAJOR;
343 istringstream versionInput(versionInfo);
344 uint16_t versionArray[VERSION_ARRAY_SIZE] = { 0 }; // major, minor, micro, nano.
345 string tmp;
346
347 while (getline(versionInput, tmp, '.')) {
348 auto ret = ExecuteVersionAnalysis(tmp, step, versionArray);
349 if (ret != SUCCESS) {
350 IMAGE_LOGE("failed to execute version analysis, ERRNO: %{public}u.", ret);
351 return ret;
352 }
353 }
354
355 if (step == VersionParseStep::STEP_NANO) {
356 // we treat nano version as optional, and default 0.
357 IMAGE_LOGD("default nano version 0.");
358 versionArray[VERSION_NANO_INDEX] = 0;
359 step = VersionParseStep::STEP_FINISHED;
360 }
361
362 if (step != VersionParseStep::STEP_FINISHED) {
363 IMAGE_LOGE("analysis version failed, step = %{public}d.", step);
364 return ERR_INVALID_PARAMETER;
365 }
366
367 versionNum.major = versionArray[VERSION_MAJOR_INDEX];
368 versionNum.minor = versionArray[VERSION_MINOR_INDEX];
369 versionNum.micro = versionArray[VERSION_MICRO_INDEX];
370 versionNum.nano = versionArray[VERSION_NANO_INDEX];
371
372 IMAGE_LOGD("analysis result: %{public}u.%{public}u.%{public}u.%{public}u.", versionNum.major,
373 versionNum.minor, versionNum.micro, versionNum.nano);
374
375 return SUCCESS;
376 }
377
ExecuteVersionAnalysis(const string & input,VersionParseStep & step,uint16_t (& versionNum)[VERSION_ARRAY_SIZE])378 uint32_t Plugin::ExecuteVersionAnalysis(const string &input, VersionParseStep &step,
379 uint16_t (&versionNum)[VERSION_ARRAY_SIZE])
380 {
381 switch (step) {
382 case VersionParseStep::STEP_MAJOR: {
383 auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MAJOR_INDEX]);
384 if (ret != SUCCESS) {
385 IMAGE_LOGE("read major version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
386 return ret;
387 }
388 step = VersionParseStep::STEP_MINOR;
389 break;
390 }
391 case VersionParseStep::STEP_MINOR: {
392 auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MINOR_INDEX]);
393 if (ret != SUCCESS) {
394 IMAGE_LOGE("read minor version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
395 return ret;
396 }
397 step = VersionParseStep::STEP_MICRO;
398 break;
399 }
400 case VersionParseStep::STEP_MICRO: {
401 auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MICRO_INDEX]);
402 if (ret != SUCCESS) {
403 IMAGE_LOGE("read micro version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
404 return ret;
405 }
406 step = VersionParseStep::STEP_NANO;
407 break;
408 }
409 case VersionParseStep::STEP_NANO: {
410 auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_NANO_INDEX]);
411 if (ret != SUCCESS) {
412 IMAGE_LOGE("read nano version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
413 return ret;
414 }
415 step = VersionParseStep::STEP_FINISHED;
416 break;
417 }
418 default: {
419 IMAGE_LOGE("read redundant version data, input: %{public}s.", input.c_str());
420 return ERR_INVALID_PARAMETER;
421 }
422 }
423
424 return SUCCESS;
425 }
426
GetUint16ValueFromDecimal(const string & source,uint16_t & result)427 uint32_t Plugin::GetUint16ValueFromDecimal(const string &source, uint16_t &result)
428 {
429 if (source.empty() || source.size() > UINT16_MAX_DECIMAL_DIGITS) {
430 IMAGE_LOGE("invalid string of uint16: %{public}s.", source.c_str());
431 return ERR_INVALID_PARAMETER;
432 }
433
434 // determine if all characters are numbers.
435 for (const auto &character : source) {
436 if (character < '0' || character > '9') {
437 IMAGE_LOGE("character out of the range of digital: %{public}s.", source.c_str());
438 return ERR_INVALID_PARAMETER;
439 }
440 }
441
442 unsigned long tmp = stoul(source);
443 if (tmp > UINT16_MAX_VALUE) {
444 IMAGE_LOGE("result out of the range of uint16: %{public}s.", source.c_str());
445 return ERR_INVALID_PARAMETER;
446 }
447
448 result = static_cast<uint16_t>(tmp);
449 return SUCCESS;
450 }
451 } // namespace MultimediaPlugin
452 } // namespace OHOS
453