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