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