• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 #include "engine_value_manager.h"
16 
17 #include <charconv>
18 #include <mutex>
19 
20 #include <core/property/intf_property_api.h>
21 #include <core/property/scoped_handle.h>
22 
23 #include <meta/api/engine/util.h>
24 #include <meta/api/make_callback.h>
25 #include <meta/ext/event_util.h>
26 #include <meta/interface/engine/intf_engine_data.h>
27 #include <meta/interface/intf_task_queue_registry.h>
28 
29 META_BEGIN_NAMESPACE()
30 
31 namespace Internal {
32 
33 template<typename Type>
ReadValueFromEngine(const EnginePropertyParams & params)34 static Type ReadValueFromEngine(const EnginePropertyParams& params)
35 {
36     Type res {};
37     if (CORE_NS::ScopedHandle<const Type> guard { params.handle.Handle() }) {
38         res = *(const Type*)((uintptr_t) & *guard + params.Offset());
39     }
40     return res;
41 }
42 
~EngineValueManager()43 EngineValueManager::~EngineValueManager()
44 {
45     ITaskQueue::WeakPtr q;
46     ITaskQueue::Token token {};
47     {
48         std::unique_lock lock { mutex_ };
49         q = queue_;
50         token = task_token_;
51     }
52     if (token) {
53         if (auto queue = q.lock()) {
54             queue->CancelTask(token);
55         }
56     }
57 }
58 
SetNotificationQueue(const ITaskQueue::WeakPtr & q)59 void EngineValueManager::SetNotificationQueue(const ITaskQueue::WeakPtr& q)
60 {
61     queue_ = q;
62 }
GetCompatibleValueInternal(IEngineValue::Ptr p,EnginePropertyParams params)63 static IEngineValueInternal::Ptr GetCompatibleValueInternal(IEngineValue::Ptr p, EnginePropertyParams params)
64 {
65     IEngineValueInternal::Ptr ret;
66     if (auto i = interface_pointer_cast<IEngineValueInternal>(p)) {
67         if (auto acc = i->GetInternalAccess()) {
68             if (acc->IsCompatible(params.property.type)) {
69                 ret = i;
70             }
71         }
72     }
73     return ret;
74 }
AddValue(EnginePropertyParams p,EngineValueOptions options)75 IEngineValue::Ptr EngineValueManager::AddValue(EnginePropertyParams p, EngineValueOptions options)
76 {
77     BASE_NS::string name { p.property.name };
78     if (!options.namePrefix.empty()) {
79         if (name.empty()) {
80             name = options.namePrefix;
81         } else {
82             name = options.namePrefix + "." + name;
83         }
84     }
85     if (auto access = META_NS::GetObjectRegistry().GetEngineData().GetInternalValueAccess(p.property.type)) {
86         IEngineValue::Ptr v;
87         if (auto it = values_.find(name); it != values_.end()) {
88             if (auto acc = GetCompatibleValueInternal(it->second.value, p)) {
89                 InterfaceUniqueLock valueLock { it->second.value };
90                 acc->SetPropertyParams(p);
91                 v = it->second.value;
92             } else {
93                 values_.erase(it);
94             }
95         }
96         if (!v) {
97             v = IEngineValue::Ptr(new EngineValue(name, access, p));
98             v->Sync(META_NS::EngineSyncDirection::FROM_ENGINE);
99             values_[name] = ValueInfo { v };
100         }
101         if (options.values) {
102             options.values->push_back(v);
103         }
104         return v;
105     }
106     CORE_LOG_W("No engine internal access type registered for '%s' (required by '%s')",
107         BASE_NS::string(p.property.type.name).c_str(), name.c_str());
108     return nullptr;
109 }
110 
ConstructValues(EnginePropertyHandle handle,EngineValueOptions options)111 bool EngineValueManager::ConstructValues(EnginePropertyHandle handle, EngineValueOptions options)
112 {
113     if (auto rh = handle.Handle()) {
114         if (auto api = rh->Owner()) {
115             std::unique_lock lock { mutex_ };
116             for (auto& prop : api->MetaData()) {
117                 EnginePropertyParams params(handle, prop, 0);
118                 params.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
119                 AddValue(params, options);
120             }
121             return true;
122         }
123     }
124     return false;
125 }
126 
ConstructValues(IValue::Ptr value,EngineValueOptions options)127 bool EngineValueManager::ConstructValues(IValue::Ptr value, EngineValueOptions options)
128 {
129     auto prefix = options.namePrefix;
130     if (prefix.empty()) {
131         if (auto i = interface_cast<IEngineValue>(value)) {
132             prefix = i->GetName();
133         }
134     }
135     if (value->IsCompatible(UidFromType<CORE_NS::IPropertyHandle*>())) {
136         if (auto p = GetValue<CORE_NS::IPropertyHandle*>(value->GetValue())) {
137             EnginePropertyHandle h { nullptr, {}, value };
138             return ConstructValues(
139                 h, EngineValueOptions { prefix, options.values, options.pushValuesDirectlyToEngine });
140         }
141     }
142     if (auto i = interface_cast<IEngineValueInternal>(value)) {
143         auto params = i->GetPropertyParams();
144         for (auto&& p : params.property.metaData.memberProperties) {
145             EnginePropertyParams propParams { params, p };
146             propParams.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
147             AddValue(propParams, EngineValueOptions { prefix, options.values });
148         }
149     }
150     return true;
151 }
152 
ConstructValue(EnginePropertyParams property,EngineValueOptions options)153 bool EngineValueManager::ConstructValue(EnginePropertyParams property, EngineValueOptions options)
154 {
155     std::unique_lock lock { mutex_ };
156     AddValue(property, options);
157     return true;
158 }
159 
ConstructValueImplArraySubs(EnginePropertyParams params,BASE_NS::string pathTaken,BASE_NS::string_view path,EngineValueOptions options)160 bool EngineValueManager::ConstructValueImplArraySubs(
161     EnginePropertyParams params, BASE_NS::string pathTaken, BASE_NS::string_view path, EngineValueOptions options)
162 {
163     if (!params.property.metaData.containerMethods) {
164         CORE_LOG_W("Cannot index non-array in property path");
165         return false;
166     }
167     auto endPos = path.find_first_of(']');
168     if (endPos == BASE_NS::string_view::npos) {
169         CORE_LOG_W("Invalid property path");
170         return false;
171     }
172     size_t index {};
173     std::from_chars_result res = std::from_chars(path.data() + 1, path.data() + endPos, index);
174     if (res.ec != std::errc {} || res.ptr != path.data() + endPos) {
175         CORE_LOG_W("Invalid property path array index");
176         return false;
177     }
178     EnginePropertyParams elementParams;
179     auto cmethods = params.property.metaData.containerMethods;
180     if (params.property.type.isArray) {
181         if (index >= params.property.count) {
182             CORE_LOG_W("Invalid property path array index, out of range");
183             return false;
184         }
185         elementParams = EnginePropertyParams(params, cmethods->property);
186         elementParams.baseOffset += elementParams.property.size * index;
187     } else {
188         if (params.containerMethods) {
189             CORE_LOG_W("Can only refer to one subscription over container");
190             return false;
191         }
192         auto handle = params.handle.Handle();
193         if (!handle) {
194             CORE_LOG_W("Invalid property handle");
195             return false;
196         }
197         auto data = (uintptr_t)handle->RLock();
198         if (!data) {
199             CORE_LOG_W("Invalid property data");
200             return false;
201         }
202         if (index >= cmethods->size(data + params.Offset())) {
203             handle->RUnlock();
204             CORE_LOG_W("Invalid property path container index, out of range");
205             return false;
206         }
207         handle->RUnlock();
208         elementParams = EnginePropertyParams(params, cmethods, index);
209     }
210     pathTaken += path.substr(0, endPos + 1);
211     path.remove_prefix(endPos + 1);
212     if (path.empty()) {
213         return ConstructValueImplAdd(elementParams, BASE_NS::move(pathTaken), options) != nullptr;
214     }
215     path.remove_prefix(1);
216     return ConstructValueImpl(elementParams, BASE_NS::move(pathTaken), path, options);
217 }
218 
ConstructValueImplAdd(EnginePropertyParams params,BASE_NS::string pathTaken,EngineValueOptions options)219 IEngineValue::Ptr EngineValueManager::ConstructValueImplAdd(
220     EnginePropertyParams params, BASE_NS::string pathTaken, EngineValueOptions options)
221 {
222     if (!options.namePrefix.empty() && !pathTaken.empty()) {
223         options.namePrefix += ".";
224     }
225     options.namePrefix += pathTaken;
226 
227     std::unique_lock lock { mutex_ };
228     return AddValue(params, options);
229 }
230 
ConstructValueImpl(EnginePropertyParams params,BASE_NS::string pathTaken,BASE_NS::string_view path,EngineValueOptions options)231 bool EngineValueManager::ConstructValueImpl(
232     EnginePropertyParams params, BASE_NS::string pathTaken, BASE_NS::string_view path, EngineValueOptions options)
233 {
234     BASE_NS::string previousPath = pathTaken;
235     if (path == params.property.name) {
236         return ConstructValueImplAdd(params, BASE_NS::move(pathTaken), options) != nullptr;
237     }
238     if (!params.property.name.empty()) {
239         if (!pathTaken.empty()) {
240             pathTaken += ".";
241         }
242         pathTaken += params.property.name;
243         path.remove_prefix(params.property.name.size());
244 
245         if (path.starts_with('[')) {
246             return ConstructValueImplArraySubs(params, BASE_NS::move(pathTaken), path, options);
247         }
248         path.remove_prefix(1);
249     }
250 
251     if (params.property.type == PROPERTYTYPE(CORE_NS::IPropertyHandle*)) {
252         if (CORE_NS::IPropertyHandle* phandle = ReadValueFromEngine<CORE_NS::IPropertyHandle*>(params)) {
253             if (auto pv = ConstructValueImplAdd(params, previousPath, options)) {
254                 EnginePropertyHandle h { nullptr, {}, pv };
255                 return ConstructValueImpl(h, BASE_NS::move(pathTaken), path, options);
256             }
257             CORE_LOG_W("Failed to construct parent engine value");
258         }
259     } else {
260         auto root = path.substr(0, path.find_first_of('.'));
261         for (auto&& p : params.property.metaData.memberProperties) {
262             if (p.name == root) {
263                 EnginePropertyParams propParams(params, p);
264                 return ConstructValueImpl(propParams, BASE_NS::move(pathTaken), path, options);
265             }
266         }
267     }
268     return false;
269 }
270 
ConstructValueImpl(EnginePropertyHandle handle,BASE_NS::string pathTaken,BASE_NS::string_view path,EngineValueOptions options)271 bool EngineValueManager::ConstructValueImpl(
272     EnginePropertyHandle handle, BASE_NS::string pathTaken, BASE_NS::string_view path, EngineValueOptions options)
273 {
274     if (auto rh = handle.Handle()) {
275         if (auto api = rh->Owner()) {
276             auto root = path.substr(0, path.find_first_of(".["));
277             if (!root.empty()) {
278                 for (auto& prop : api->MetaData()) {
279                     if (prop.name == root) {
280                         EnginePropertyParams params(handle, prop, 0);
281                         params.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
282                         return ConstructValueImpl(params, BASE_NS::move(pathTaken), path, options);
283                     }
284                 }
285             }
286         }
287     }
288     return false;
289 }
290 
ConstructValue(EnginePropertyHandle handle,BASE_NS::string_view path,EngineValueOptions options)291 bool EngineValueManager::ConstructValue(
292     EnginePropertyHandle handle, BASE_NS::string_view path, EngineValueOptions options)
293 {
294     return ConstructValueImpl(handle, "", BASE_NS::string(path), options);
295 }
296 
RemoveValue(BASE_NS::string_view name)297 bool EngineValueManager::RemoveValue(BASE_NS::string_view name)
298 {
299     std::unique_lock lock { mutex_ };
300     auto it = values_.find(name);
301     bool ret = it != values_.end();
302     if (ret) {
303         values_.erase(it);
304     }
305     return ret;
306 }
307 
RemoveAll()308 void EngineValueManager::RemoveAll()
309 {
310     std::unique_lock lock { mutex_ };
311     values_.clear();
312 }
313 
ConstructProperty(BASE_NS::string_view name) const314 IProperty::Ptr EngineValueManager::ConstructProperty(BASE_NS::string_view name) const
315 {
316     IEngineValue::Ptr value;
317     {
318         std::shared_lock lock { mutex_ };
319         auto it = values_.find(name);
320         if (it != values_.end()) {
321             value = it->second.value;
322         }
323     }
324     return PropertyFromEngineValue(name, value);
325 }
326 
ConstructAllProperties() const327 BASE_NS::vector<IProperty::Ptr> EngineValueManager::ConstructAllProperties() const
328 {
329     BASE_NS::vector<IProperty::Ptr> ret;
330     std::shared_lock lock { mutex_ };
331     for (auto&& v : values_) {
332         ret.push_back(PropertyFromEngineValue(v.first, v.second.value));
333     }
334     return ret;
335 }
336 
GetEngineValue(BASE_NS::string_view name) const337 IEngineValue::Ptr EngineValueManager::GetEngineValue(BASE_NS::string_view name) const
338 {
339     std::shared_lock lock { mutex_ };
340     auto it = values_.find(name);
341     return it != values_.end() ? it->second.value : nullptr;
342 }
343 
GetAllEngineValues() const344 BASE_NS::vector<IEngineValue::Ptr> EngineValueManager::GetAllEngineValues() const
345 {
346     BASE_NS::vector<IEngineValue::Ptr> ret;
347     std::shared_lock lock { mutex_ };
348     for (auto&& v : values_) {
349         ret.push_back(v.second.value);
350     }
351     return ret;
352 }
353 
NotifySyncs()354 void EngineValueManager::NotifySyncs()
355 {
356     BASE_NS::vector<IEngineValue::Ptr> values;
357     {
358         std::unique_lock lock { mutex_ };
359         for (auto&& v : values_) {
360             if (auto i = interface_cast<IEngineValueInternal>(v.second.value); i && i->ResetPendingNotify()) {
361                 values.push_back(v.second.value);
362             }
363         }
364         task_token_ = {};
365     }
366     for (auto&& v : values) {
367         if (auto noti = interface_cast<INotifyOnChange>(v)) {
368             Invoke<IOnChanged>(noti->OnChanged());
369         }
370     }
371 }
372 
SyncValue(const IEngineValue::Ptr & value,EngineSyncDirection dir)373 static AnyReturnValue SyncValue(const IEngineValue::Ptr& value, EngineSyncDirection dir)
374 {
375     InterfaceUniqueLock valueLock { value };
376     if (auto i = interface_pointer_cast<IEngineValueInternal>(value)) {
377         // if this engine value depends on another one, sync the dependency first
378         if (auto pv = interface_pointer_cast<IEngineValue>(i->GetPropertyParams().handle.parentValue)) {
379             SyncValue(pv, dir);
380         }
381     }
382     return value->Sync(dir);
383 }
384 
Sync(EngineSyncDirection dir)385 bool EngineValueManager::Sync(EngineSyncDirection dir)
386 {
387     bool ret = true;
388     bool notify = false;
389     {
390         std::unique_lock lock { mutex_ };
391         for (auto&& v : values_) {
392             auto res = SyncValue(v.second.value, dir);
393             if (res && res != AnyReturn::NOTHING_TO_DO) {
394                 notify = true;
395             }
396             ret = ret && res;
397         }
398         notify = notify && !task_token_;
399         if (notify && !queue_.expired()) {
400             if (auto queue = queue_.lock()) {
401                 task_token_ = queue->AddTask(MakeCallback<ITaskQueueTask>([this] {
402                     NotifySyncs();
403                     return false;
404                 }));
405             } else {
406                 CORE_LOG_E("Invalid task queue id");
407             }
408             notify = false;
409         }
410     }
411     if (notify) {
412         NotifySyncs();
413     }
414     return ret;
415 }
416 } // namespace Internal
417 
418 META_END_NAMESPACE()
419