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_mgr.h"
17 #include "image_log.h"
18 #include "impl_class.h"
19 #include "plugin.h"
20 #include "plugin_class_base.h"
21 
22 #undef LOG_DOMAIN
23 #define LOG_DOMAIN LOG_TAG_DOMAIN_ID_PLUGIN
24 
25 #undef LOG_TAG
26 #define LOG_TAG "ImplClassMgr"
27 
28 namespace OHOS {
29 namespace MultimediaPlugin {
30 using nlohmann::json;
31 using std::list;
32 using std::map;
33 using std::multimap;
34 using std::mutex;
35 using std::set;
36 using std::shared_ptr;
37 using std::string;
38 using std::weak_ptr;
39 
AddClass(weak_ptr<Plugin> & plugin,const json & classInfo)40 uint32_t ImplClassMgr::AddClass(weak_ptr<Plugin> &plugin, const json &classInfo)
41 {
42     shared_ptr<ImplClass> implClass = std::make_shared<ImplClass>();
43     if (implClass == nullptr) {
44         IMAGE_LOGE("AddClass: failed to create ImplClass.");
45         return ERR_INTERNAL;
46     }
47 
48     auto ret = implClass->Register(plugin, classInfo);
49     if (ret != SUCCESS) {
50         IMAGE_LOGE("AddClass: failed to register impClass.ERRNO: %{public}u.", ret);
51         return ret;
52     }
53 
54     const string &key = implClass->GetClassName();
55     if (key.empty()) {
56         IMAGE_LOGE("AddClass: empty className.");
57         return ERR_INTERNAL;
58     }
59 
60     IMAGE_LOGD("AddClass: insert Class: %{public}s.", key.c_str());
61     classMultimap_.insert(NameClassMultimap::value_type(&key, implClass));
62 
63     // for fast search by service flag
64     const set<uint32_t> &services = implClass->GetServices();
65     for (const uint32_t &srv : services) {
66         IMAGE_LOGD("AddClass: insert service: %{public}u.", srv);
67         srvSearchMultimap_.insert(ServiceClassMultimap::value_type(srv, implClass));
68     }
69 
70     return SUCCESS;
71 }
72 
DeleteClass(const weak_ptr<Plugin> & plugin)73 void ImplClassMgr::DeleteClass(const weak_ptr<Plugin> &plugin)
74 {
75     // delete all ImplClass under the specified plugin.
76     auto targetPlugin = plugin.lock();
77 
78     for (auto iter = srvSearchMultimap_.begin(); iter != srvSearchMultimap_.end();) {
79         auto tmpPlugin = iter->second->GetPluginRef().lock();
80         if (tmpPlugin != targetPlugin) {
81             ++iter;
82             continue;
83         }
84         iter = srvSearchMultimap_.erase(iter);
85     }
86 
87     for (auto iter = classMultimap_.begin(); iter != classMultimap_.end();) {
88         auto tmpPlugin = iter->second->GetPluginRef().lock();
89         if (tmpPlugin != targetPlugin) {
90             ++iter;
91             continue;
92         }
93         iter = classMultimap_.erase(iter);
94     }
95 }
96 
CreateObject(uint16_t interfaceID,const string & className,uint32_t & errorCode)97 PluginClassBase *ImplClassMgr::CreateObject(uint16_t interfaceID, const string &className, uint32_t &errorCode)
98 {
99     IMAGE_LOGD("create object iid: %{public}hu, className: %{public}s.", interfaceID, className.c_str());
100 
101     NameClassMultimap::iterator iter = classMultimap_.lower_bound(&className);
102     NameClassMultimap::iterator endIter = classMultimap_.upper_bound(&className);
103     if (iter == endIter) {
104         IMAGE_LOGE("failed to find matching class by className: %{public}s.", className.c_str());
105         errorCode = ERR_MATCHING_PLUGIN;
106         return nullptr;
107     }
108 
109     for (; iter != endIter; ++iter) {
110         if (iter->second->IsSupport(interfaceID)) {
111             return iter->second->CreateObject(errorCode);
112         }
113     }
114 
115     // no this class
116     IMAGE_LOGE("failed to find matching class for iid: %{public}hu, className: %{public}s.", interfaceID,
117         className.c_str());
118     errorCode = ERR_MATCHING_PLUGIN;
119     return nullptr;
120 }
121 
CreateObject(uint16_t interfaceID,uint16_t serviceType,const map<string,AttrData> & capabilities,const PriorityScheme & priorityScheme,uint32_t & errorCode)122 PluginClassBase *ImplClassMgr::CreateObject(uint16_t interfaceID, uint16_t serviceType,
123                                             const map<string, AttrData> &capabilities,
124                                             const PriorityScheme &priorityScheme, uint32_t &errorCode)
125 {
126     uint32_t serviceFlag = ImplClass::MakeServiceFlag(interfaceID, serviceType);
127     list<shared_ptr<ImplClass>> candidates;
128 
129     IMAGE_LOGD("create object iid: %{public}u, serviceType: %{public}u.", interfaceID, serviceType);
130 
131     auto iter = srvSearchMultimap_.lower_bound(serviceFlag);
132     auto endIter = srvSearchMultimap_.upper_bound(serviceFlag);
133     for (; iter != endIter; ++iter) {
134         shared_ptr<ImplClass> &temp = iter->second;
135         if ((!capabilities.empty()) && (!temp->IsCompatible(capabilities))) {
136             continue;
137         }
138         candidates.push_back(temp);
139     }
140 
141     shared_ptr<ImplClass> target = SearchByPriority(candidates, priorityScheme);
142     if (target == nullptr) {
143         IMAGE_LOGD("failed to find class by priority.");
144         errorCode = ERR_MATCHING_PLUGIN;
145         return nullptr;
146     }
147 
148     IMAGE_LOGD("search by priority result, className: %{public}s.", target->GetClassName().c_str());
149     return target->CreateObject(errorCode);
150 }
151 
ImplClassMgrGetClassInfo(uint16_t interfaceID,uint16_t serviceType,const std::map<std::string,AttrData> & capabilities,std::vector<ClassInfo> & classesInfo)152 uint32_t ImplClassMgr::ImplClassMgrGetClassInfo(uint16_t interfaceID, uint16_t serviceType,
153                                                 const std::map<std::string, AttrData> &capabilities,
154                                                 std::vector<ClassInfo> &classesInfo)
155 {
156     // get service flag by interfaceID and serviceType
157     uint32_t serviceFlag = ImplClass::MakeServiceFlag(interfaceID, serviceType);
158 
159     IMAGE_LOGD("get classinfo iid: %{public}u, serviceType: %{public}u.", interfaceID, serviceType);
160     auto iter = srvSearchMultimap_.lower_bound(serviceFlag);
161     auto endIter = srvSearchMultimap_.upper_bound(serviceFlag);
162     if (iter == endIter) {
163         IMAGE_LOGE("failed to get class by serviceFlag, iid: %{public}u, serviceType: %{public}u.",
164             interfaceID, serviceType);
165         return ERR_MATCHING_PLUGIN;
166     }
167 
168     for (; iter != endIter; ++iter) {
169         shared_ptr<ImplClass> &temp = iter->second;
170         if ((capabilities.size() != 0) && (!temp->IsCompatible(capabilities))) {
171             continue;
172         }
173         // after multiple filtering, there are only a few instances here, which will not cause massive logs.
174         IMAGE_LOGD("found by serviceFlag & capabilities, className: %{public}s.", temp->GetClassName().c_str());
175         ClassInfo classInfo;
176         classInfo.packageName = temp->GetPackageName();
177         classInfo.className = temp->GetClassName();
178         classInfo.priority = temp->GetPriority();
179         classInfo.capabilities = temp->GetCapability();
180         classesInfo.emplace_back(std::move(classInfo));
181     }
182 
183     if (classesInfo.empty()) {
184         IMAGE_LOGE("failed to get class by capabilities, iid: %{public}u, serviceType: %{public}u.", interfaceID,
185             serviceType);
186         return ERR_MATCHING_PLUGIN;
187     }
188 
189     return SUCCESS;
190 }
191 
GetImplClass(const string & packageName,const string & className)192 shared_ptr<ImplClass> ImplClassMgr::GetImplClass(const string &packageName, const string &className)
193 {
194     IMAGE_LOGD("search ImplClass, className: %{public}s.", className.c_str());
195     shared_ptr<ImplClass> implClass = nullptr;
196     auto iter = classMultimap_.lower_bound(&className);
197     auto endIter = classMultimap_.upper_bound(&className);
198     for (; iter != endIter; ++iter) {
199         if (packageName == iter->second->GetPackageName()) {
200             implClass = iter->second;
201             break;
202         }
203     }
204 
205     if (implClass == nullptr) {
206         IMAGE_LOGE("failed to get ImplClass, className: %{public}s.", className.c_str());
207     }
208 
209     return implClass;
210 }
211 
212 // ------------------------------- private method -------------------------------
ImplClassMgr()213 ImplClassMgr::ImplClassMgr()
214 {}
215 
~ImplClassMgr()216 ImplClassMgr::~ImplClassMgr()
217 {}
218 
SearchByPriority(const list<shared_ptr<ImplClass>> & candidates,const PriorityScheme & priorityScheme)219 shared_ptr<ImplClass> ImplClassMgr::SearchByPriority(const list<shared_ptr<ImplClass>> &candidates,
220                                                      const PriorityScheme &priorityScheme)
221 {
222     auto size = candidates.size();
223     if (size == 0) {  // 0 means class no candidate,  return empty directly.
224         IMAGE_LOGD("SearchByPriority: candidates size is zero.");
225         return nullptr;
226     }
227 
228     if (size == 1) {  // 1 means class only one candidate, no need to handle priority, return directly.
229         return candidates.front();
230     }
231 
232     if (priorityScheme.GetPriorityType() == PriorityType::PRIORITY_TYPE_NULL) {
233         // no attribute priority policy, we only compare static priority
234         return SearchSimplePriority(candidates);
235     }
236 
237     PriorityType priorityType = priorityScheme.GetPriorityType();
238     const string &attrKey = priorityScheme.GetAttrKey();
239 
240     auto targetIter = candidates.begin();
241     // targetAttr is allowed to be empty.
242     // when the target ImplClass does not have this attribute, the value of targetAttr is null,
243     // and the subsequent priority comparison process will judge and handle this situation.
244     const AttrData *targetAttr = ((*targetIter)->GetCapability)(attrKey);
245 
246     auto tempIter = targetIter;
247     for (++tempIter; tempIter != candidates.end(); ++tempIter) {
248         const AttrData *attrData = ((*tempIter)->GetCapability)(attrKey);
249         if (attrData == nullptr) {
250             continue;
251         }
252 
253         if (targetAttr == nullptr) {
254             targetIter = tempIter;
255             targetAttr = attrData;
256             continue;
257         }
258 
259         // the result value is used later, the targetIter and targetAttr assignment structures cannot be merged,
260         // and the the merged logic will not understand well.
261         uint32_t result = ComparePriority(*attrData, *targetAttr, priorityType);
262         if (result == ERR_COMP_HIGHER) {
263             targetIter = tempIter;
264             targetAttr = attrData;
265             continue;
266         }
267 
268         // if the priority attribute are equal, we further compare the static priority.
269         if (result == ERR_COMP_EQUAL) {
270             if (((*tempIter)->GetPriority()) > ((*targetIter)->GetPriority())) {
271                 targetIter = tempIter;
272                 targetAttr = attrData;
273             }
274         }
275     }
276 
277     return *targetIter;
278 }
279 
SearchSimplePriority(const list<shared_ptr<ImplClass>> & candidates)280 shared_ptr<ImplClass> ImplClassMgr::SearchSimplePriority(const list<shared_ptr<ImplClass>> &candidates)
281 {
282     if (candidates.size() == 0) {
283         IMAGE_LOGE("SearchSimplePriority: candidates size is zero.");
284         return nullptr;
285     }
286     auto targetIter = candidates.begin();
287     auto tempIter = targetIter;
288 
289     for (++tempIter; tempIter != candidates.end(); ++tempIter) {
290         if (((*tempIter)->GetPriority()) > ((*targetIter)->GetPriority())) {
291             targetIter = tempIter;
292         }
293     }
294 
295     return *targetIter;
296 }
297 
ComparePriority(const AttrData & lhs,const AttrData & rhs,PriorityType type)298 uint32_t ImplClassMgr::ComparePriority(const AttrData &lhs, const AttrData &rhs, PriorityType type)
299 {
300     if (lhs.GetType() != rhs.GetType()) {
301         IMAGE_LOGE("compare between different types, %{public}d and %{public}d.", lhs.GetType(),
302             rhs.GetType());
303         return ERR_COMP_ERROR;
304     }
305 
306     switch (lhs.GetType()) {
307         case AttrDataType::ATTR_DATA_NULL: {
308             return ERR_COMP_EQUAL;
309         }
310         case AttrDataType::ATTR_DATA_BOOL: {
311             return CompareBoolPriority(lhs, rhs, type);
312         }
313         case AttrDataType::ATTR_DATA_UINT32:
314         case AttrDataType::ATTR_DATA_UINT32_SET:
315         case AttrDataType::ATTR_DATA_UINT32_RANGE: {
316             return CompareUint32Priority(lhs, rhs, type);
317         }
318         case AttrDataType::ATTR_DATA_STRING:
319         case AttrDataType::ATTR_DATA_STRING_SET: {
320             return CompareStringPriority(lhs, rhs, type);
321         }
322         default: {
323             IMAGE_LOGE("invalid data type: %{public}d.", lhs.GetType());
324             return ERR_COMP_ERROR;
325         }
326     }
327 }
328 
329 // for the bool type, the meaning of the size is unknown. we artificially define true greater than false here.
CompareBoolPriority(const AttrData & lhs,const AttrData & rhs,PriorityType type)330 uint32_t ImplClassMgr::CompareBoolPriority(const AttrData &lhs, const AttrData &rhs, PriorityType type)
331 {
332     bool lhsValue = false;
333     bool rhsValue = false;
334 
335     if ((lhs.GetValue(lhsValue) != SUCCESS) || (rhs.GetValue(rhsValue) != SUCCESS)) {
336         IMAGE_LOGE("CompareBoolPriority: failed to get attribute value.");
337         return ERR_COMP_ERROR;
338     }
339 
340     if (type == PriorityType::PRIORITY_ORDER_BY_ATTR_ASCENDING) {
341         if (lhsValue) {
342             if (!rhsValue) {
343                 return ERR_COMP_LOWER;
344             }
345             return ERR_COMP_EQUAL;
346         }
347 
348         if (rhsValue) {
349             return ERR_COMP_HIGHER;
350         }
351 
352         return ERR_COMP_EQUAL;
353     }
354 
355     if (lhsValue) {
356         if (!rhsValue) {
357             return ERR_COMP_HIGHER;
358         }
359         return ERR_COMP_EQUAL;
360     }
361 
362     if (rhsValue) {
363         return ERR_COMP_LOWER;
364     }
365 
366     return ERR_COMP_EQUAL;
367 }
368 
CompareUint32Priority(const AttrData & lhs,const AttrData & rhs,PriorityType type)369 uint32_t ImplClassMgr::CompareUint32Priority(const AttrData &lhs, const AttrData &rhs, PriorityType type)
370 {
371     uint32_t lhsValue = 0;
372     uint32_t rhsValue = 0;
373 
374     if (type == PriorityType::PRIORITY_ORDER_BY_ATTR_ASCENDING) {
375         if ((lhs.GetMinValue(lhsValue) != SUCCESS) || (rhs.GetMinValue(rhsValue) != SUCCESS)) {
376             IMAGE_LOGE("CompareUint32Priority: failed to get attribute min value.");
377             return ERR_COMP_ERROR;
378         }
379 
380         if (lhsValue < rhsValue) {
381             return ERR_COMP_HIGHER;
382         }
383 
384         if (lhsValue == rhsValue) {
385             return ERR_COMP_EQUAL;
386         }
387 
388         return ERR_COMP_LOWER;
389     }
390 
391     if ((lhs.GetMaxValue(lhsValue) != SUCCESS) || (rhs.GetMaxValue(rhsValue) != SUCCESS)) {
392         IMAGE_LOGE("CompareUint32Priority: failed to get attribute max value.");
393         return ERR_COMP_ERROR;
394     }
395 
396     if (lhsValue < rhsValue) {
397         return ERR_COMP_LOWER;
398     }
399 
400     if (lhsValue == rhsValue) {
401         return ERR_COMP_EQUAL;
402     }
403 
404     return ERR_COMP_HIGHER;
405 }
406 
CompareStringPriority(const AttrData & lhs,const AttrData & rhs,PriorityType type)407 uint32_t ImplClassMgr::CompareStringPriority(const AttrData &lhs, const AttrData &rhs, PriorityType type)
408 {
409     const string *lhsValue = nullptr;
410     const string *rhsValue = nullptr;
411 
412     if (type == PriorityType::PRIORITY_ORDER_BY_ATTR_ASCENDING) {
413         if ((lhs.GetMinValue(lhsValue) != SUCCESS) || (rhs.GetMinValue(rhsValue) != SUCCESS)) {
414             IMAGE_LOGE("CompareStringPriority: failed to get attribute min value.");
415             return ERR_COMP_ERROR;
416         }
417 
418         if (lhsValue == nullptr || rhsValue == nullptr) {
419             IMAGE_LOGE("CompareStringPriority: value is null.");
420             return ERR_COMP_ERROR;
421         }
422 
423         if (*lhsValue < *rhsValue) {
424             return ERR_COMP_HIGHER;
425         }
426 
427         if (*lhsValue == *rhsValue) {
428             return ERR_COMP_EQUAL;
429         }
430 
431         return ERR_COMP_LOWER;
432     }
433 
434     if ((lhs.GetMaxValue(lhsValue) != SUCCESS) || (rhs.GetMaxValue(rhsValue) != SUCCESS)) {
435         IMAGE_LOGE("CompareStringPriority: failed to get attribute max value.");
436         return ERR_COMP_ERROR;
437     }
438 
439     if (lhsValue == nullptr || rhsValue == nullptr) {
440         IMAGE_LOGE("CompareStringPriority: value is null.");
441         return ERR_COMP_ERROR;
442     }
443 
444     if (*lhsValue < *rhsValue) {
445         return ERR_COMP_LOWER;
446     }
447 
448     if (*lhsValue == *rhsValue) {
449         return ERR_COMP_EQUAL;
450     }
451 
452     return ERR_COMP_HIGHER;
453 }
454 } // namespace MultimediaPlugin
455 } // namespace OHOS
456