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