• 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 
16 #include "engine_value_manager.h"
17 
18 #include <charconv>
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 };
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.handle, p, params.Offset() };
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.type.isArray || !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     if (index >= params.property.count) {
179         CORE_LOG_W("Invalid property path array index, out of range");
180         return false;
181     }
182 
183     EnginePropertyParams elementParams { params.handle, params.property.metaData.containerMethods->property,
184         params.Offset() };
185     elementParams.baseOffset += elementParams.property.size * index;
186     elementParams.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
187 
188     pathTaken += path.substr(0, endPos + 1);
189     path.remove_prefix(endPos + 1);
190     if (path.empty()) {
191         return ConstructValueImplAdd(elementParams, BASE_NS::move(pathTaken), options) != nullptr;
192     }
193     path.remove_prefix(1);
194     return ConstructValueImpl(elementParams, BASE_NS::move(pathTaken), path, options);
195 }
196 
ConstructValueImplAdd(EnginePropertyParams params,BASE_NS::string pathTaken,EngineValueOptions options)197 IEngineValue::Ptr EngineValueManager::ConstructValueImplAdd(
198     EnginePropertyParams params, BASE_NS::string pathTaken, EngineValueOptions options)
199 {
200     if (!options.namePrefix.empty() && !pathTaken.empty()) {
201         options.namePrefix += ".";
202     }
203     options.namePrefix += pathTaken;
204 
205     std::unique_lock lock { mutex_ };
206     return AddValue(params, options);
207 }
208 
ConstructValueImpl(EnginePropertyParams params,BASE_NS::string pathTaken,BASE_NS::string_view path,EngineValueOptions options)209 bool EngineValueManager::ConstructValueImpl(
210     EnginePropertyParams params, BASE_NS::string pathTaken, BASE_NS::string_view path, EngineValueOptions options)
211 {
212     BASE_NS::string previousPath = pathTaken;
213     if (path == params.property.name) {
214         return ConstructValueImplAdd(params, BASE_NS::move(pathTaken), options) != nullptr;
215     }
216     if (!params.property.name.empty()) {
217         if (!pathTaken.empty()) {
218             pathTaken += ".";
219         }
220         pathTaken += params.property.name;
221         path.remove_prefix(params.property.name.size());
222 
223         if (path.starts_with('[')) {
224             return ConstructValueImplArraySubs(params, BASE_NS::move(pathTaken), path, options);
225         }
226         path.remove_prefix(1);
227     }
228 
229     if (params.property.type == PROPERTYTYPE(CORE_NS::IPropertyHandle*)) {
230         if (CORE_NS::IPropertyHandle* phandle = ReadValueFromEngine<CORE_NS::IPropertyHandle*>(params)) {
231             if (auto pv = ConstructValueImplAdd(params, previousPath, options)) {
232                 EnginePropertyHandle h { nullptr, {}, pv };
233                 return ConstructValueImpl(h, BASE_NS::move(pathTaken), path, options);
234             }
235             CORE_LOG_W("Failed to construct parent engine value");
236         }
237     } else {
238         auto root = path.substr(0, path.find_first_of('.'));
239         for (auto&& p : params.property.metaData.memberProperties) {
240             if (p.name == root) {
241                 EnginePropertyParams propParams { params.handle, p, params.Offset() };
242                 propParams.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
243                 return ConstructValueImpl(propParams, BASE_NS::move(pathTaken), path, options);
244             }
245         }
246     }
247     return false;
248 }
249 
ConstructValueImpl(EnginePropertyHandle handle,BASE_NS::string pathTaken,BASE_NS::string_view path,EngineValueOptions options)250 bool EngineValueManager::ConstructValueImpl(
251     EnginePropertyHandle handle, BASE_NS::string pathTaken, BASE_NS::string_view path, EngineValueOptions options)
252 {
253     if (auto rh = handle.Handle()) {
254         if (auto api = rh->Owner()) {
255             auto root = path.substr(0, path.find_first_of(".["));
256             if (!root.empty()) {
257                 for (auto& prop : api->MetaData()) {
258                     if (prop.name == root) {
259                         EnginePropertyParams params { handle, prop };
260                         params.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
261                         return ConstructValueImpl(params, BASE_NS::move(pathTaken), path, options);
262                     }
263                 }
264             }
265         }
266     }
267     return false;
268 }
269 
ConstructValue(EnginePropertyHandle handle,BASE_NS::string_view path,EngineValueOptions options)270 bool EngineValueManager::ConstructValue(
271     EnginePropertyHandle handle, BASE_NS::string_view path, EngineValueOptions options)
272 {
273     return ConstructValueImpl(handle, "", BASE_NS::string(path), options);
274 }
275 
RemoveValue(BASE_NS::string_view name)276 bool EngineValueManager::RemoveValue(BASE_NS::string_view name)
277 {
278     std::unique_lock lock { mutex_ };
279     auto it = values_.find(name);
280     bool ret = it != values_.end();
281     if (ret) {
282         values_.erase(it);
283     }
284     return ret;
285 }
286 
RemoveAll()287 void EngineValueManager::RemoveAll()
288 {
289     std::unique_lock lock { mutex_ };
290     values_.clear();
291 }
292 
ConstructProperty(BASE_NS::string_view name) const293 IProperty::Ptr EngineValueManager::ConstructProperty(BASE_NS::string_view name) const
294 {
295     IEngineValue::Ptr value;
296     {
297         std::shared_lock lock { mutex_ };
298         auto it = values_.find(name);
299         if (it != values_.end()) {
300             value = it->second.value;
301         }
302     }
303     return PropertyFromEngineValue(name, value);
304 }
305 
ConstructAllProperties() const306 BASE_NS::vector<IProperty::Ptr> EngineValueManager::ConstructAllProperties() const
307 {
308     BASE_NS::vector<IProperty::Ptr> ret;
309     std::shared_lock lock { mutex_ };
310     for (auto&& v : values_) {
311         ret.push_back(PropertyFromEngineValue(v.first, v.second.value));
312     }
313     return ret;
314 }
315 
GetEngineValue(BASE_NS::string_view name) const316 IEngineValue::Ptr EngineValueManager::GetEngineValue(BASE_NS::string_view name) const
317 {
318     std::shared_lock lock { mutex_ };
319     auto it = values_.find(name);
320     return it != values_.end() ? it->second.value : nullptr;
321 }
322 
GetAllEngineValues() const323 BASE_NS::vector<IEngineValue::Ptr> EngineValueManager::GetAllEngineValues() const
324 {
325     BASE_NS::vector<IEngineValue::Ptr> ret;
326     std::shared_lock lock { mutex_ };
327     for (auto&& v : values_) {
328         ret.push_back(v.second.value);
329     }
330     return ret;
331 }
332 
NotifySyncs()333 void EngineValueManager::NotifySyncs()
334 {
335     BASE_NS::vector<IEngineValue::Ptr> values;
336     {
337         std::unique_lock lock { mutex_ };
338         for (auto&& v : values_) {
339             if (auto i = interface_cast<IEngineValueInternal>(v.second.value); i && i->ResetPendingNotify()) {
340                 values.push_back(v.second.value);
341             }
342         }
343         task_token_ = {};
344     }
345     for (auto&& v : values) {
346         if (auto noti = interface_cast<INotifyOnChange>(v)) {
347             Invoke<IOnChanged>(noti->OnChanged());
348         }
349     }
350 }
351 
SyncValue(const IEngineValue::Ptr & value,EngineSyncDirection dir)352 static AnyReturnValue SyncValue(const IEngineValue::Ptr& value, EngineSyncDirection dir)
353 {
354     InterfaceUniqueLock valueLock { value };
355     if (auto i = interface_pointer_cast<IEngineValueInternal>(value)) {
356         // if this engine value depends on another one, sync the dependency first
357         if (auto pv = interface_pointer_cast<IEngineValue>(i->GetPropertyParams().handle.parentValue)) {
358             SyncValue(pv, dir);
359         }
360     }
361     return value->Sync(dir);
362 }
363 
Sync(EngineSyncDirection dir)364 bool EngineValueManager::Sync(EngineSyncDirection dir)
365 {
366     bool ret = true;
367     bool notify = false;
368     {
369         std::unique_lock lock { mutex_ };
370         for (auto&& v : values_) {
371             auto res = SyncValue(v.second.value, dir);
372             if (res && res != AnyReturn::NOTHING_TO_DO) {
373                 notify = true;
374             }
375             ret = ret && res;
376         }
377         notify = notify && !task_token_;
378         if (notify && !queue_.expired()) {
379             if (auto queue = queue_.lock()) {
380                 task_token_ = queue->AddTask(MakeCallback<ITaskQueueTask>([this] {
381                     NotifySyncs();
382                     return false;
383                 }));
384             } else {
385                 CORE_LOG_E("Invalid task queue id");
386             }
387             notify = false;
388         }
389     }
390     if (notify) {
391         NotifySyncs();
392     }
393     return ret;
394 }
395 } // namespace Internal
396 
397 META_END_NAMESPACE()
398