• 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 "impl_class.h"
17 #include <algorithm>
18 #include "image_log.h"
19 #include "impl_class_key.h"
20 #include "json_helper.h"
21 #include "plugin.h"
22 #include "plugin_class_base.h"
23 #include "plugin_common_type.h"
24 #include "plugin_export.h"
25 
26 #undef LOG_DOMAIN
27 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
28 
29 #undef LOG_TAG
30 #define LOG_TAG "ImplClass"
31 
32 namespace OHOS {
33 namespace MultimediaPlugin {
34 using nlohmann::json;
35 using std::map;
36 using std::recursive_mutex;
37 using std::set;
38 using std::shared_ptr;
39 using std::size_t;
40 using std::string;
41 using std::weak_ptr;
42 string ImplClass::emptyString_;
43 
ImplClass()44 ImplClass::ImplClass() : selfKey_(*this)
45 {}
46 
Register(const weak_ptr<Plugin> & plugin,const json & classInfo)47 uint32_t ImplClass::Register(const weak_ptr<Plugin> &plugin, const json &classInfo)
48 {
49     if (state_ != ClassState::CLASS_STATE_UNREGISTER) {
50         // repeat registration
51         IMAGE_LOGI("repeat registration.");
52         return ERR_INTERNAL;
53     }
54 
55     if (JsonHelper::GetStringValue(classInfo, "className", className_) != SUCCESS) {
56         IMAGE_LOGE("read className failed.");
57         return ERR_INVALID_PARAMETER;
58     }
59     IMAGE_LOGD("register class: %{public}s.", className_.c_str());
60 
61     CHECK_ERROR_RETURN_RET_LOG(!AnalysisServices(classInfo), ERR_INVALID_PARAMETER,
62         "failed to analysis services for class %{public}s.", className_.c_str());
63 
64     uint32_t result = JsonHelper::GetUint16Value(classInfo, "priority", priority_);
65     if (result != SUCCESS) {
66         CHECK_ERROR_RETURN_RET_LOG(result != ERR_NO_TARGET, ERR_INVALID_PARAMETER,
67             "read priority failed, result: %{public}u.", result);
68         // priority is optional, and default zero.
69         priority_ = 0;
70     }
71     IMAGE_LOGD("get class priority: %{public}u.", priority_);
72 
73     CHECK_ERROR_RETURN_RET_LOG(!AnalysisMaxInstance(classInfo), ERR_INVALID_PARAMETER,
74         "failed to analysis maxInstance for class %{public}s.", className_.c_str());
75     IMAGE_LOGD("get class maxInstance: %{public}u.", maxInstance_);
76 
77     if (JsonHelper::CheckElementExistence(classInfo, "capabilities") == SUCCESS) {
78         capability_.SetCapability(classInfo["capabilities"]);
79     }
80     pluginRef_ = plugin;
81     state_ = ClassState::CLASS_STATE_REGISTERED;
82     return SUCCESS;
83 }
84 
CreateObject(uint32_t & errorCode)85 PluginClassBase *ImplClass::CreateObject(uint32_t &errorCode)
86 {
87     errorCode = ERR_INTERNAL;
88     if (state_ != ClassState::CLASS_STATE_REGISTERED) {
89         IMAGE_LOGE("failed to create for unregistered, className: %{public}s.", className_.c_str());
90         return nullptr;
91     }
92 
93     auto sharedPlugin = pluginRef_.lock();
94     if (sharedPlugin == nullptr) {
95         IMAGE_LOGE("failed to dereference Plugin, className: %{public}s.", className_.c_str());
96         return nullptr;
97     }
98 
99     IMAGE_LOGD("create object, className: %{public}s.", className_.c_str());
100 
101     std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
102     if (maxInstance_ != INSTANCE_NO_LIMIT_NUM && instanceNum_ >= maxInstance_) {
103         IMAGE_LOGE("failed to create for limit, currentNum: %{public}u, maxNum: %{public}u, \
104             className: %{public}s.", instanceNum_, maxInstance_, className_.c_str());
105         guard.unlock();
106         errorCode = ERR_INSTANCE_LIMIT;
107         return nullptr;
108     }
109 
110     if (instanceNum_ == 0) {
111         if (sharedPlugin->Ref() != SUCCESS) {
112             return nullptr;
113         }
114     }
115 
116     PluginClassBase *object = DoCreateObject(sharedPlugin);
117     if (object == nullptr) {
118         IMAGE_LOGE("create object result null, className: %{public}s.", className_.c_str());
119         if (instanceNum_ == 0) {
120             sharedPlugin->DeRef();
121         }
122         return nullptr;
123     }
124 
125     ++instanceNum_;
126     IMAGE_LOGD("create object success, InstanceNum: %{public}u.", instanceNum_);
127     guard.unlock();
128 
129     errorCode = SUCCESS;
130     return object;
131 }
132 
GetPluginRef() const133 weak_ptr<Plugin> ImplClass::GetPluginRef() const
134 {
135     if (state_ != ClassState::CLASS_STATE_REGISTERED) {
136         return weak_ptr<Plugin>();
137     }
138 
139     return pluginRef_;
140 }
141 
GetClassName() const142 const string &ImplClass::GetClassName() const
143 {
144     return className_;
145 }
146 
GetPackageName() const147 const string &ImplClass::GetPackageName() const
148 {
149     if (state_ != ClassState::CLASS_STATE_REGISTERED) {
150         IMAGE_LOGE("get package name, className: %{public}s, state error: %{public}d.", className_.c_str(), state_);
151         return emptyString_;
152     }
153 
154     auto sharedPlugin = pluginRef_.lock();
155     if (sharedPlugin == nullptr) {
156         IMAGE_LOGE("get package name, failed to dereference Plugin, className: %{public}s.", className_.c_str());
157         return emptyString_;
158     }
159 
160     return sharedPlugin->GetPackageName();
161 }
162 
IsSupport(uint16_t interfaceID) const163 bool ImplClass::IsSupport(uint16_t interfaceID) const
164 {
165     IMAGE_LOGD("search for support iid: %{public}u, className: %{public}s.", interfaceID, className_.c_str());
166     for (uint32_t serviceFlag : services_) {
167         if (MakeIID(serviceFlag) == interfaceID) {
168             return true;
169         }
170     }
171 
172     IMAGE_LOGD("there is no matching interfaceID");
173     return false;
174 }
175 
OnObjectDestroy()176 void ImplClass::OnObjectDestroy()
177 {
178     // this situation does not happen in design.
179     // the process context can guarantee that this will not happen.
180     // the judgment statement here is for protection and positioning purposes only.
181     if (state_ != ClassState::CLASS_STATE_REGISTERED) {
182         IMAGE_LOGE("failed to destroy object because class unregistered, className: %{public}s.", className_.c_str());
183         return;
184     }
185 
186     std::unique_lock<std::recursive_mutex> guard(dynDataLock_);
187     // this situation does not happen in design.
188     if (instanceNum_ == 0) {
189         guard.unlock();
190         IMAGE_LOGE("destroy object while instanceNum is zero.");
191         return;
192     }
193 
194     --instanceNum_;
195 
196     auto sharedPlugin = pluginRef_.lock();
197     // this situation does not happen in design.
198     if (sharedPlugin == nullptr) {
199         guard.unlock();
200         IMAGE_LOGE("destroy object failed because failed to dereference Plugin, className: %{public}s.",
201             className_.c_str());
202         return;
203     }
204 
205     IMAGE_LOGD("destroy object: className: %{public}s", className_.c_str());
206     if (instanceNum_ == 0) {
207         sharedPlugin->DeRef();
208     }
209 
210     IMAGE_LOGD("destroy object success, InstanceNum: %{public}u.", instanceNum_);
211 }
212 
GetServices() const213 const set<uint32_t> &ImplClass::GetServices() const
214 {
215     return services_;
216 }
217 
IsCompatible(const map<string,AttrData> & caps) const218 bool ImplClass::IsCompatible(const map<string, AttrData> &caps) const
219 {
220     return capability_.IsCompatible(caps);
221 }
222 
GetCapability(const string & key) const223 const AttrData *ImplClass::GetCapability(const string &key) const
224 {
225     if (state_ != ClassState::CLASS_STATE_REGISTERED) {
226         return nullptr;
227     }
228 
229     return capability_.GetCapability(key);
230 }
231 
GetCapability() const232 const std::map<std::string, AttrData> &ImplClass::GetCapability() const
233 {
234     return capability_.GetCapability();
235 }
236 
237 // ------------------------------- private method -------------------------------
AnalysisServices(const json & classInfo)238 bool ImplClass::AnalysisServices(const json &classInfo)
239 {
240     size_t serviceNum;
241     if (JsonHelper::GetArraySize(classInfo, "services", serviceNum) != SUCCESS) {
242         IMAGE_LOGE("read array size of services failed.");
243         return false;
244     }
245     IMAGE_LOGD("class service num: %{public}zu.", serviceNum);
246 
247     uint16_t interfaceID;
248 #ifndef PLUGIN_FLAG_RTTI_ENABLE
249     uint32_t lastInterfaceID = UINT32_MAX_VALUE;
250 #endif
251     uint16_t serviceType;
252     bool serviceAdded = false;
253     const json &servicesInfo = classInfo["services"];
254     for (size_t i = 0; i < serviceNum; i++) {
255         const json &serviceInfo = servicesInfo[i];
256         if (JsonHelper::GetUint16Value(serviceInfo, "interfaceID", interfaceID) != SUCCESS) {
257             IMAGE_LOGE("read interfaceID failed at %{public}zu.", i);
258 #ifndef PLUGIN_FLAG_RTTI_ENABLE
259             // when -frtti is not enable, to ensure correct base class side-to-side conversion, we require that
260             // the plugin class inherit only one service interface class and the PluginClassBase class,
261             // while the location of the service interface class is in front of the PluginClassBase.
262             // below, we check only one business interface class is allowed to inherit.
263             IMAGE_LOGE("no valid service info or encounter the risk of more than one business \
264                                 interface base class.");
265             return false;
266 #else
267             continue;
268 #endif
269         }
270 
271 #ifndef PLUGIN_FLAG_RTTI_ENABLE
272         // check only one business interface class is allowed to inherit.
273         bool cond = lastInterfaceID != UINT32_MAX_VALUE && lastInterfaceID != interfaceID;
274         CHECK_ERROR_RETURN_RET_LOG(cond, false, "more than one business interface base class.");
275         lastInterfaceID = interfaceID;
276 #endif
277         uint32_t result = JsonHelper::GetUint16Value(serviceInfo, "serviceType", serviceType);
278         if (result != SUCCESS) {
279             if (result != ERR_NO_TARGET) {
280                 IMAGE_LOGE("read serviceType failed at %{public}zu.", i);
281                 continue;
282             }
283             // serviceType is optional, and default zero.
284             serviceType = 0;
285         }
286 
287         IMAGE_LOGD("insert service iid: %{public}hu, serviceType: %{public}hu.", interfaceID, serviceType);
288         services_.insert(MakeServiceFlag(interfaceID, serviceType));
289         serviceAdded = true;
290     }
291 
292     return serviceAdded;
293 }
294 
AnalysisMaxInstance(const json & classInfo)295 bool ImplClass::AnalysisMaxInstance(const json &classInfo)
296 {
297     uint32_t result = JsonHelper::GetUint16Value(classInfo, "maxInstance", maxInstance_);
298     if (result == SUCCESS) {
299         IMAGE_LOGD("class maxInstance num: %{public}u.", maxInstance_);
300         if (maxInstance_ == 0) {
301             IMAGE_LOGE("class maxInstance num is invalid zero.");
302             return false;
303         }
304         return true;
305     }
306 
307     if (result != ERR_NO_TARGET) {
308         IMAGE_LOGE("read maxInstance failed.");
309         return false;
310     }
311 
312     // maxInstance is optional, and value for this case is not limited.
313     maxInstance_ = INSTANCE_NO_LIMIT_NUM;
314     return true;
315 }
316 
CfiFactory(PluginCreateFunc factory,const string & className)317 PluginClassBase *CfiFactory(PluginCreateFunc factory, const string &className) __attribute__((no_sanitize("cfi")))
318 {
319     return factory(className);
320 }
321 
DoCreateObject(shared_ptr<Plugin> & plugin)322 PluginClassBase *ImplClass::DoCreateObject(shared_ptr<Plugin> &plugin) __attribute__((no_sanitize("cfi")))
323 {
324     // since the plugin library may be unloaded and reloaded, the pointer cannot guarantee a constant value,
325     // so it is reread every time here.
326     PluginCreateFunc factory = plugin->GetCreateFunc();
327     if (factory == nullptr) {
328         IMAGE_LOGE("failed to get create func, className: %{public}s.", className_.c_str());
329         return nullptr;
330     }
331 
332     PluginClassBase *pluginBaseObj = CfiFactory(factory, className_);
333     CHECK_ERROR_RETURN_RET_LOG(pluginBaseObj == nullptr, nullptr,
334         "create object result null, className: %{public}s.", className_.c_str());
335 
336 #ifndef PLUGIN_FLAG_RTTI_ENABLE
337     // when -frtti is not enable, to ensure correct base class side-to-side conversion,
338     // we require that the plugin class inherit only one service interface class and the PluginClassBase class,
339     // while the location of the service interface class is in front of the PluginClassBase.
340     // below, we check the inherited position constraint.
341     void *obj = dynamic_cast<void *>(pluginBaseObj);  // adjust pointer position when multiple inheritance.
342     if (obj == pluginBaseObj) {
343         // PluginClassBase is the first base class, not allowed.
344         IMAGE_LOGE("service interface class is not the first base class. className: %{public}s.", className_.c_str());
345         delete pluginBaseObj;
346         return nullptr;
347     }
348 #endif
349 
350     if (pluginBaseObj->SetImplClassKey(selfKey_) != PluginClassBase::MAGIC_CODE) {
351         IMAGE_LOGE("failed to set key, className: %{public}s.", className_.c_str());
352         delete pluginBaseObj;
353         return nullptr;
354     }
355 
356     return pluginBaseObj;
357 }
358 } // namespace MultimediaPlugin
359 } // namespace OHOS
360