• 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 #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         guard.unlock();
77         IMAGE_LOGI("repeat registration.");
78         return ERR_INTERNAL;
79     }
80 
81     auto ret = RegisterMetadata(metadata, plugin);
82     if (ret != SUCCESS) {
83         guard.unlock();
84         IMAGE_LOGE("failed to register metadata, ERRNO: %{public}u.", ret);
85         return ret;
86     }
87 
88     libraryPath_ = std::move(libraryPath);
89     plugin_ = plugin;
90     state_ = PluginState::PLUGIN_STATE_REGISTERED;
91     return SUCCESS;
92 }
93 
CfiStartFunc_(PluginStartFunc startFunc_)94 bool CfiStartFunc_(PluginStartFunc startFunc_) __attribute__((no_sanitize("cfi")))
95 {
96     return startFunc_();
97 }
98 
Ref()99 uint32_t Plugin::Ref()
100 {
101     // once the client make a ref, it can use the plugin at any time,
102     // so we do the necessary preparations here.
103     std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
104     if (state_ == PluginState::PLUGIN_STATE_REGISTERED) {
105         if (ResolveLibrary() != SUCCESS) {
106             guard.unlock();
107             IMAGE_LOGE("failed to resolve library.");
108             return ERR_GENERAL;
109         }
110         state_ = PluginState::PLUGIN_STATE_RESOLVED;
111     }
112 
113     if (state_ == PluginState::PLUGIN_STATE_RESOLVED) {
114         // maybe asynchronous, or for reduce the locking time
115         state_ = PluginState::PLUGIN_STATE_STARTING;
116         if (!CfiStartFunc_(startFunc_)) {
117             IMAGE_LOGE("failed to start plugin.");
118             FreeLibrary();
119             state_ = PluginState::PLUGIN_STATE_REGISTERED;
120             return ERR_GENERAL;
121         }
122         state_ = PluginState::PLUGIN_STATE_ACTIVE;
123     }
124 
125     if (state_ != PluginState::PLUGIN_STATE_ACTIVE) {
126         IMAGE_LOGE("plugin ref: state error, state: %{public}d.", state_);
127         return ERR_GENERAL;
128     }
129 
130     ++refNum_;
131     IMAGE_LOGD("plugin refNum: %{public}d.", refNum_);
132     return SUCCESS;
133 }
134 
DeRef()135 void Plugin::DeRef()
136 {
137     std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
138     if (refNum_ == 0) {
139         // this situation does not happen in design.
140         // the process context can guarantee that this will not happen.
141         // the judgment statement here is for protection and positioning purposes only.
142         guard.unlock();
143         IMAGE_LOGE("DeRef while RefNum is zero.");
144         return;
145     }
146 
147     --refNum_;
148     IMAGE_LOGD("plugin refNum: %{public}d.", refNum_);
149 }
150 
Block()151 void Plugin::Block()
152 {
153     // used to protect against business interruptions during plugin upgrades.
154     // after the plugin is upgraded, if the original .so is being used,
155     // it cannot be released immediately and should be locked,
156     // and the subsequent requests are migrated to the new .so.
157     std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
158     blocked_ = true;
159 }
160 
Unblock()161 void Plugin::Unblock()
162 {
163     std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
164     blocked_ = false;
165 }
166 
GetCreateFunc()167 PluginCreateFunc Plugin::GetCreateFunc()
168 {
169     std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
170     if ((state_ != PluginState::PLUGIN_STATE_ACTIVE) || (refNum_ == 0)) {
171         // In this case, we can't guarantee that the pointer is lasting valid.
172         IMAGE_LOGE("failed to get create func, State: %{public}d, RefNum: %{public}u.", state_, refNum_);
173         return nullptr;
174     }
175 
176     return createFunc_;
177 }
178 
GetLibraryPath() const179 const string &Plugin::GetLibraryPath() const
180 {
181     return libraryPath_;
182 }
183 
GetPackageName() const184 const string &Plugin::GetPackageName() const
185 {
186     return packageName_;
187 }
188 
189 // ------------------------------- private method -------------------------------
ResolveLibrary()190 uint32_t Plugin::ResolveLibrary()
191 {
192     std::string pluginStartSymbol = "PluginExternalStart";
193     std::string pluginStopSymbol = "PluginExternalStop";
194     std::string pluginCreateSymbol = "PluginExternalCreate";
195 
196 #ifdef _WIN32
197     hDll = platformAdp_.AdpLoadLibrary(libraryPath_);
198     if (hDll == NULL) {
199         IMAGE_LOGE("failed to load library.");
200         return ERR_GENERAL;
201     }
202 
203     startFunc_ = (PluginStartFunc)platformAdp_.AdpGetSymAddress(hDll, pluginStartSymbol);
204     stopFunc_ = (PluginStopFunc)platformAdp_.AdpGetSymAddress(hDll, pluginStopSymbol);
205     createFunc_ = (PluginCreateFunc)platformAdp_.AdpGetSymAddress(hDll, pluginCreateSymbol);
206     if (startFunc_ == NULL || stopFunc_ == NULL || createFunc_ == NULL) {
207         IMAGE_LOGE("failed to get export symbol for the plugin.");
208         FreeLibrary();
209         return ERR_GENERAL;
210     }
211 
212     return SUCCESS;
213 #elif defined(A_PLATFORM) || defined(IOS_PLATFORM)
214     startFunc_ = PluginExternalStart;
215     stopFunc_ = PluginExternalStop;
216     createFunc_ = PluginExternalCreate;
217     return SUCCESS;
218 #else
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(A_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;
280     metadata >> root;
281     if (JsonHelper::GetStringValue(root, "packageName", packageName_) != SUCCESS) {
282         IMAGE_LOGE("read packageName failed.");
283         return ERR_INVALID_PARAMETER;
284     }
285 
286     string targetVersion;
287     if (JsonHelper::GetStringValue(root, "targetVersion", targetVersion) != SUCCESS) {
288         IMAGE_LOGE("read targetVersion failed.");
289         return ERR_INVALID_PARAMETER;
290     }
291     uint32_t ret = CheckTargetVersion(targetVersion);
292     if (ret != SUCCESS) {
293         // target version is not compatible
294         IMAGE_LOGE("check targetVersion failed, Version: %{public}s, ERRNO: %{public}u.", targetVersion.c_str(), ret);
295         return ret;
296     }
297 
298     if (JsonHelper::GetStringValue(root, "version", version_) != SUCCESS) {
299         IMAGE_LOGE("read version failed.");
300         return ERR_INVALID_PARAMETER;
301     }
302     VersionNum versionNum;
303     ret = AnalyzeVersion(version_, versionNum);
304     if (ret != SUCCESS) {
305         IMAGE_LOGE("check version failed, Version: %{public}s, ERRNO: %{public}u.", version_.c_str(), ret);
306         return ret;
307     }
308 
309     size_t classNum;
310     if (JsonHelper::GetArraySize(root, "classes", classNum) != SUCCESS) {
311         IMAGE_LOGE("get array size of classes failed.");
312         return ERR_INVALID_PARAMETER;
313     }
314     IMAGE_LOGD("parse class num: %{public}zu.", classNum);
315     for (size_t i = 0; i < classNum; i++) {
316         const json &classInfo = root["classes"][i];
317         if (implClassMgr_.AddClass(plugin, classInfo) != SUCCESS) {
318             IMAGE_LOGE("failed to add class, index: %{public}zu.", i);
319             continue;
320         }
321     }
322 
323     return SUCCESS;
324 }
325 
CheckTargetVersion(const string & targetVersion)326 uint32_t Plugin::CheckTargetVersion(const string &targetVersion)
327 {
328     VersionNum versionNum;
329     auto ret = AnalyzeVersion(targetVersion, versionNum);
330     if (ret != SUCCESS) {
331         IMAGE_LOGE("failed to analyze version, ERRNO: %{public}u.", ret);
332         return ret;
333     }
334 
335     return SUCCESS;
336 }
337 
AnalyzeVersion(const string & versionInfo,VersionNum & versionNum)338 uint32_t Plugin::AnalyzeVersion(const string &versionInfo, VersionNum &versionNum)
339 {
340     VersionParseStep step = VersionParseStep::STEP_MAJOR;
341     istringstream versionInput(versionInfo);
342     uint16_t versionArray[VERSION_ARRAY_SIZE] = { 0 };  // major, minor, micro, nano.
343     string tmp;
344 
345     while (getline(versionInput, tmp, '.')) {
346         auto ret = ExecuteVersionAnalysis(tmp, step, versionArray);
347         if (ret != SUCCESS) {
348             IMAGE_LOGE("failed to execute version analysis, ERRNO: %{public}u.", ret);
349             return ret;
350         }
351     }
352 
353     if (step == VersionParseStep::STEP_NANO) {
354         // we treat nano version as optional, and default 0.
355         IMAGE_LOGD("default nano version 0.");
356         versionArray[VERSION_NANO_INDEX] = 0;
357         step = VersionParseStep::STEP_FINISHED;
358     }
359 
360     if (step != VersionParseStep::STEP_FINISHED) {
361         IMAGE_LOGE("analysis version failed, step = %{public}d.", step);
362         return ERR_INVALID_PARAMETER;
363     }
364 
365     versionNum.major = versionArray[VERSION_MAJOR_INDEX];
366     versionNum.minor = versionArray[VERSION_MINOR_INDEX];
367     versionNum.micro = versionArray[VERSION_MICRO_INDEX];
368     versionNum.nano = versionArray[VERSION_NANO_INDEX];
369 
370     IMAGE_LOGD("analysis result: %{public}u.%{public}u.%{public}u.%{public}u.", versionNum.major,
371         versionNum.minor, versionNum.micro, versionNum.nano);
372 
373     return SUCCESS;
374 }
375 
ExecuteVersionAnalysis(const string & input,VersionParseStep & step,uint16_t (& versionNum)[VERSION_ARRAY_SIZE])376 uint32_t Plugin::ExecuteVersionAnalysis(const string &input, VersionParseStep &step,
377                                         uint16_t (&versionNum)[VERSION_ARRAY_SIZE])
378 {
379     switch (step) {
380         case VersionParseStep::STEP_MAJOR: {
381             auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MAJOR_INDEX]);
382             if (ret != SUCCESS) {
383                 IMAGE_LOGE("read major version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
384                 return ret;
385             }
386             step = VersionParseStep::STEP_MINOR;
387             break;
388         }
389         case VersionParseStep::STEP_MINOR: {
390             auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MINOR_INDEX]);
391             if (ret != SUCCESS) {
392                 IMAGE_LOGE("read minor version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
393                 return ret;
394             }
395             step = VersionParseStep::STEP_MICRO;
396             break;
397         }
398         case VersionParseStep::STEP_MICRO: {
399             auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_MICRO_INDEX]);
400             if (ret != SUCCESS) {
401                 IMAGE_LOGE("read micro version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
402                 return ret;
403             }
404             step = VersionParseStep::STEP_NANO;
405             break;
406         }
407         case VersionParseStep::STEP_NANO: {
408             auto ret = GetUint16ValueFromDecimal(input, versionNum[VERSION_NANO_INDEX]);
409             if (ret != SUCCESS) {
410                 IMAGE_LOGE("read nano version failed, input: %{public}s, ERRNO: %{public}u.", input.c_str(), ret);
411                 return ret;
412             }
413             step = VersionParseStep::STEP_FINISHED;
414             break;
415         }
416         default: {
417             IMAGE_LOGE("read redundant version data, input: %{public}s.", input.c_str());
418             return ERR_INVALID_PARAMETER;
419         }
420     }
421 
422     return SUCCESS;
423 }
424 
GetUint16ValueFromDecimal(const string & source,uint16_t & result)425 uint32_t Plugin::GetUint16ValueFromDecimal(const string &source, uint16_t &result)
426 {
427     if (source.empty() || source.size() > UINT16_MAX_DECIMAL_DIGITS) {
428         IMAGE_LOGE("invalid string of uint16: %{public}s.", source.c_str());
429         return ERR_INVALID_PARAMETER;
430     }
431 
432     // determine if all characters are numbers.
433     for (const auto &character : source) {
434         if (character < '0' || character > '9') {
435             IMAGE_LOGE("character out of the range of digital: %{public}s.", source.c_str());
436             return ERR_INVALID_PARAMETER;
437         }
438     }
439 
440     unsigned long tmp = stoul(source);
441     if (tmp > UINT16_MAX_VALUE) {
442         IMAGE_LOGE("result out of the range of uint16: %{public}s.", source.c_str());
443         return ERR_INVALID_PARAMETER;
444     }
445 
446     result = static_cast<uint16_t>(tmp);
447     return SUCCESS;
448 }
449 } // namespace MultimediaPlugin
450 } // namespace OHOS
451