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