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