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