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