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