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 <core/property/intf_property_api.h>
18 #include <core/property/scoped_handle.h>
19 
20 #include <meta/api/make_callback.h>
21 #include <meta/interface/engine/intf_engine_data.h>
22 #include <meta/interface/intf_task_queue_registry.h>
23 
24 META_BEGIN_NAMESPACE()
25 
26 namespace Internal {
27 
28 template<typename Type>
ReadValueFromEngine(const EnginePropertyParams & params)29 static Type ReadValueFromEngine(const EnginePropertyParams& params)
30 {
31     Type res {};
32     CORE_NS::ScopedHandle<const Type> guard { params.handle };
33     if (guard) {
34         res = *(const Type*)((uintptr_t) & *guard + params.Offset());
35     }
36     return res;
37 }
38 
~EngineValueManager()39 EngineValueManager::~EngineValueManager()
40 {
41     ITaskQueue::WeakPtr q;
42     ITaskQueue::Token token {};
43     {
44         std::unique_lock lock { mutex_ };
45         q = queue_;
46         token = task_token_;
47     }
48     if (token) {
49         if (auto queue = q.lock()) {
50             queue->CancelTask(token);
51         }
52     }
53 }
54 
SetNotificationQueue(const ITaskQueue::WeakPtr & q)55 void EngineValueManager::SetNotificationQueue(const ITaskQueue::WeakPtr& q)
56 {
57     queue_ = q;
58 }
GetCompatibleValueInternal(IEngineValue::Ptr p,EnginePropertyParams params)59 static IEngineValueInternal::Ptr GetCompatibleValueInternal(IEngineValue::Ptr p, EnginePropertyParams params)
60 {
61     IEngineValueInternal::Ptr ret;
62     if (auto i = interface_pointer_cast<IEngineValueInternal>(p)) {
63         if (auto acc = i->GetInternalAccess()) {
64             if (acc->IsCompatible(params.property.type)) {
65                 ret = i;
66             }
67         }
68     }
69     return ret;
70 }
AddValue(EnginePropertyParams p,EngineValueOptions options)71 void EngineValueManager::AddValue(EnginePropertyParams p, EngineValueOptions options)
72 {
73     BASE_NS::string name { p.property.name };
74     if (!options.namePrefix.empty()) {
75         name = options.namePrefix + "." + name;
76     }
77     if (auto access = META_NS::GetObjectRegistry().GetEngineData().GetInternalValueAccess(p.property.type)) {
78         auto it = values_.find(name);
79         if (it != values_.end()) {
80             if (auto acc = GetCompatibleValueInternal(it->second.value, p)) {
81                 InterfaceUniqueLock valueLock { it->second.value };
82                 acc->SetPropertyParams(p);
83                 return;
84             }
85             values_.erase(it);
86         }
87         auto v = IEngineValue::Ptr(new EngineValue(name, access, p));
88         v->Sync(META_NS::EngineSyncDirection::FROM_ENGINE);
89         values_[name] = ValueInfo { v };
90         if (options.values) {
91             options.values->push_back(v);
92         }
93     } else {
94         CORE_LOG_W("No engine internal access type registered for '%s' (required by '%s')",
95             BASE_NS::string(p.property.type.name).c_str(), name.c_str());
96     }
97 }
98 
ConstructValues(CORE_NS::IPropertyHandle * handle,EngineValueOptions options)99 bool EngineValueManager::ConstructValues(CORE_NS::IPropertyHandle* handle, EngineValueOptions options)
100 {
101     if (handle) {
102         if (auto api = handle->Owner()) {
103             std::unique_lock lock { mutex_ };
104             for (auto& prop : api->MetaData()) {
105                 EnginePropertyParams params { handle, prop };
106                 params.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
107                 AddValue(params, options);
108             }
109             return true;
110         }
111     }
112     return false;
113 }
ConstructValues(IValue::Ptr value,EngineValueOptions options)114 bool EngineValueManager::ConstructValues(IValue::Ptr value, EngineValueOptions options)
115 {
116     auto prefix = options.namePrefix;
117     if (prefix.empty()) {
118         if (auto i = interface_cast<IEngineValue>(value)) {
119             prefix = i->GetName();
120         }
121     }
122     if (value->IsCompatible(UidFromType<CORE_NS::IPropertyHandle*>())) {
123         if (auto p = GetValue<CORE_NS::IPropertyHandle*>(value->GetValue())) {
124             return ConstructValues(
125                 p, EngineValueOptions { prefix, options.values, options.pushValuesDirectlyToEngine });
126         }
127     }
128     if (auto i = interface_cast<IEngineValueInternal>(value)) {
129         auto params = i->GetPropertyParams();
130         for (auto&& p : params.property.metaData.memberProperties) {
131             EnginePropertyParams propParams { params.handle, p, params.Offset() };
132             propParams.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
133             AddValue(propParams, EngineValueOptions { prefix, options.values });
134         }
135     }
136     return true;
137 }
ConstructValue(EnginePropertyParams property,EngineValueOptions options)138 bool EngineValueManager::ConstructValue(EnginePropertyParams property, EngineValueOptions options)
139 {
140     std::unique_lock lock { mutex_ };
141     AddValue(property, options);
142     return true;
143 }
ConstructValueImpl(EnginePropertyParams params,BASE_NS::string pathTaken,BASE_NS::string_view path,EngineValueOptions options)144 bool EngineValueManager::ConstructValueImpl(
145     EnginePropertyParams params, BASE_NS::string pathTaken, BASE_NS::string_view path, EngineValueOptions options)
146 {
147     if (path == params.property.name) {
148         if (!options.namePrefix.empty() && !pathTaken.empty()) {
149             options.namePrefix += ".";
150         }
151         options.namePrefix += pathTaken;
152         std::unique_lock lock { mutex_ };
153         AddValue(params, options);
154         return true;
155     }
156     path.remove_prefix(params.property.name.size() + 1);
157     if (!pathTaken.empty()) {
158         pathTaken += ".";
159     }
160     pathTaken += params.property.name;
161     if (params.property.type == PROPERTYTYPE(CORE_NS::IPropertyHandle*)) {
162         if (CORE_NS::IPropertyHandle* h = ReadValueFromEngine<CORE_NS::IPropertyHandle*>(params)) {
163             return ConstructValueImpl(h, BASE_NS::move(pathTaken), path, options);
164         }
165     } else {
166         auto root = path.substr(0, path.find_first_of('.'));
167         for (auto&& p : params.property.metaData.memberProperties) {
168             if (p.name == root) {
169                 EnginePropertyParams propParams { params.handle, p, params.Offset() };
170                 propParams.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
171                 return ConstructValueImpl(propParams, BASE_NS::move(pathTaken), path, options);
172             }
173         }
174     }
175     return false;
176 }
ConstructValueImpl(CORE_NS::IPropertyHandle * handle,BASE_NS::string pathTaken,BASE_NS::string_view path,EngineValueOptions options)177 bool EngineValueManager::ConstructValueImpl(
178     CORE_NS::IPropertyHandle* handle, BASE_NS::string pathTaken, BASE_NS::string_view path, EngineValueOptions options)
179 {
180     if (!handle) {
181         return false;
182     }
183     if (auto api = handle->Owner()) {
184         auto root = path.substr(0, path.find_first_of('.'));
185         if (!root.empty()) {
186             for (auto& prop : api->MetaData()) {
187                 if (prop.name == root) {
188                     EnginePropertyParams params { handle, prop };
189                     params.pushValueToEngineDirectly = options.pushValuesDirectlyToEngine;
190                     return ConstructValueImpl(params, BASE_NS::move(pathTaken), path, options);
191                 }
192             }
193         }
194     }
195     return false;
196 }
ConstructValue(CORE_NS::IPropertyHandle * handle,BASE_NS::string_view path,EngineValueOptions options)197 bool EngineValueManager::ConstructValue(
198     CORE_NS::IPropertyHandle* handle, BASE_NS::string_view path, EngineValueOptions options)
199 {
200     return ConstructValueImpl(handle, "", BASE_NS::string(path), options);
201 }
RemoveValue(BASE_NS::string_view name)202 bool EngineValueManager::RemoveValue(BASE_NS::string_view name)
203 {
204     std::unique_lock lock { mutex_ };
205     auto it = values_.find(name);
206     bool ret = it != values_.end();
207     if (ret) {
208         values_.erase(it);
209     }
210     return ret;
211 }
RemoveAll()212 void EngineValueManager::RemoveAll()
213 {
214     std::unique_lock lock { mutex_ };
215     values_.clear();
216 }
217 
PropertyFromValue(BASE_NS::string_view name,const IEngineValue::Ptr & value) const218 IProperty::Ptr EngineValueManager::PropertyFromValue(BASE_NS::string_view name, const IEngineValue::Ptr& value) const
219 {
220     IProperty::Ptr ret;
221     if (auto internal = interface_cast<IEngineValueInternal>(value)) {
222         ret = GetObjectRegistry().GetPropertyRegister().Create(META_NS::ClassId::StackProperty, name);
223         if (auto i = interface_cast<IPropertyInternalAny>(ret)) {
224             i->SetInternalAny(internal->GetInternalAccess()->CreateAny());
225         }
226         if (auto i = interface_cast<IStackProperty>(ret)) {
227             i->PushValue(value);
228         }
229     }
230     return ret;
231 }
232 
ConstructProperty(BASE_NS::string_view name) const233 IProperty::Ptr EngineValueManager::ConstructProperty(BASE_NS::string_view name) const
234 {
235     IEngineValue::Ptr value;
236     {
237         std::shared_lock lock { mutex_ };
238         auto it = values_.find(name);
239         if (it != values_.end()) {
240             value = it->second.value;
241         }
242     }
243     return PropertyFromValue(name, value);
244 }
245 
ConstructAllProperties() const246 BASE_NS::vector<IProperty::Ptr> EngineValueManager::ConstructAllProperties() const
247 {
248     BASE_NS::vector<IProperty::Ptr> ret;
249     std::shared_lock lock { mutex_ };
250     for (auto&& v : values_) {
251         ret.push_back(PropertyFromValue(v.first, v.second.value));
252     }
253     return ret;
254 }
255 
GetEngineValue(BASE_NS::string_view name) const256 IEngineValue::Ptr EngineValueManager::GetEngineValue(BASE_NS::string_view name) const
257 {
258     std::shared_lock lock { mutex_ };
259     auto it = values_.find(name);
260     return it != values_.end() ? it->second.value : nullptr;
261 }
262 
GetAllEngineValues() const263 BASE_NS::vector<IEngineValue::Ptr> EngineValueManager::GetAllEngineValues() const
264 {
265     BASE_NS::vector<IEngineValue::Ptr> ret;
266     std::shared_lock lock { mutex_ };
267     for (auto&& v : values_) {
268         ret.push_back(v.second.value);
269     }
270     return ret;
271 }
272 
NotifySyncs()273 void EngineValueManager::NotifySyncs()
274 {
275     BASE_NS::vector<IEngineValue::Ptr> values;
276     {
277         std::unique_lock lock { mutex_ };
278         for (auto&& v : values_) {
279             if (v.second.notify) {
280                 values.push_back(v.second.value);
281                 v.second.notify = false;
282             }
283         }
284         task_token_ = {};
285     }
286     for (auto&& v : values) {
287         if (auto noti = interface_cast<INotifyOnChange>(v)) {
288             Invoke<IOnChanged>(noti->OnChanged());
289         }
290     }
291 }
292 
Sync(EngineSyncDirection dir)293 bool EngineValueManager::Sync(EngineSyncDirection dir)
294 {
295     bool ret = true;
296     bool notify = false;
297     {
298         std::unique_lock lock { mutex_ };
299         for (auto&& v : values_) {
300             InterfaceUniqueLock valueLock { v.second.value };
301             auto res = v.second.value->Sync(dir);
302             if (res && res != AnyReturn::NOTHING_TO_DO) {
303                 v.second.notify = true;
304                 notify = true;
305             }
306             ret = ret && res;
307         }
308         notify = notify && !task_token_;
309         if (notify && !queue_.expired()) {
310             if (auto queue = queue_.lock()) {
311                 task_token_ = queue->AddTask(MakeCallback<ITaskQueueTask>([this] {
312                     NotifySyncs();
313                     return false;
314                 }));
315             } else {
316                 CORE_LOG_E("Invalid task queue id");
317             }
318             notify = false;
319         }
320     }
321     if (notify) {
322         NotifySyncs();
323     }
324     return ret;
325 }
326 } // namespace Internal
327 
328 META_END_NAMESPACE()
329