18bf80f4bSopenharmony_ci/* 28bf80f4bSopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd. 38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License. 58bf80f4bSopenharmony_ci * You may obtain a copy of the License at 68bf80f4bSopenharmony_ci * 78bf80f4bSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 88bf80f4bSopenharmony_ci * 98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and 138bf80f4bSopenharmony_ci * limitations under the License. 148bf80f4bSopenharmony_ci */ 158bf80f4bSopenharmony_ci#include "startable_object_controller.h" 168bf80f4bSopenharmony_ci 178bf80f4bSopenharmony_ci#include <meta/api/future.h> 188bf80f4bSopenharmony_ci#include <meta/api/iteration.h> 198bf80f4bSopenharmony_ci#include <meta/api/make_callback.h> 208bf80f4bSopenharmony_ci#include <meta/api/task.h> 218bf80f4bSopenharmony_ci#include <meta/api/util.h> 228bf80f4bSopenharmony_ci#include <meta/interface/intf_content.h> 238bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue_registry.h> 248bf80f4bSopenharmony_ci#include <meta/interface/property/property_events.h> 258bf80f4bSopenharmony_ci 268bf80f4bSopenharmony_ciMETA_BEGIN_NAMESPACE() 278bf80f4bSopenharmony_ci 288bf80f4bSopenharmony_cibool StartableObjectController::Build(const IMetadata::Ptr& data) 298bf80f4bSopenharmony_ci{ 308bf80f4bSopenharmony_ci auto& reg = GetObjectRegistry(); 318bf80f4bSopenharmony_ci observer_ = reg.Create<IObjectHierarchyObserver>(ClassId::ObjectHierarchyObserver); 328bf80f4bSopenharmony_ci CORE_ASSERT(observer_); 338bf80f4bSopenharmony_ci clock_ = reg.Create<IClock>(ClassId::SystemClock); 348bf80f4bSopenharmony_ci CORE_ASSERT(clock_); 358bf80f4bSopenharmony_ci 368bf80f4bSopenharmony_ci observer_->OnHierarchyChanged()->AddHandler( 378bf80f4bSopenharmony_ci MakeCallback<IOnHierarchyChanged>(this, &StartableObjectController::HierarchyChanged)); 388bf80f4bSopenharmony_ci 398bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(StartBehavior)->OnChanged()->AddHandler(MakeCallback<IOnChanged>([this]() { 408bf80f4bSopenharmony_ci if (META_ACCESS_PROPERTY_VALUE(StartBehavior) == StartBehavior::AUTOMATIC) { 418bf80f4bSopenharmony_ci // If StartBehavior changes to AUTOMATIC, start all AUTOMATIC startables 428bf80f4bSopenharmony_ci StartAll(ControlBehavior::CONTROL_AUTOMATIC); 438bf80f4bSopenharmony_ci } 448bf80f4bSopenharmony_ci })); 458bf80f4bSopenharmony_ci 468bf80f4bSopenharmony_ci defaultTickerQueue_ = META_NS::GetObjectRegistry().Create<ITaskQueue>(ClassId::ThreadedTaskQueue); 478bf80f4bSopenharmony_ci CORE_ASSERT(defaultTickerQueue_); 488bf80f4bSopenharmony_ci tickerTask_ = META_NS::MakeCallback<ITaskQueueTask>([this]() { 498bf80f4bSopenharmony_ci TickAll(clock_->GetTime()); 508bf80f4bSopenharmony_ci return true; // Recurring 518bf80f4bSopenharmony_ci }); 528bf80f4bSopenharmony_ci CORE_ASSERT(tickerTask_); 538bf80f4bSopenharmony_ci 548bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(TickInterval) 558bf80f4bSopenharmony_ci ->OnChanged() 568bf80f4bSopenharmony_ci ->AddHandler(MakeCallback<IOnChanged>(this, &StartableObjectController::UpdateTicker)); 578bf80f4bSopenharmony_ci META_ACCESS_PROPERTY(TickOrder)->OnChanged()->AddHandler( 588bf80f4bSopenharmony_ci MakeCallback<IOnChanged>(this, &StartableObjectController::InvalidateTickables)); 598bf80f4bSopenharmony_ci UpdateTicker(); 608bf80f4bSopenharmony_ci return true; 618bf80f4bSopenharmony_ci} 628bf80f4bSopenharmony_ci 638bf80f4bSopenharmony_civoid StartableObjectController::Destroy() 648bf80f4bSopenharmony_ci{ 658bf80f4bSopenharmony_ci if (tickerQueue_ && tickerToken_) { 668bf80f4bSopenharmony_ci tickerQueue_->CancelTask(tickerToken_); 678bf80f4bSopenharmony_ci } 688bf80f4bSopenharmony_ci InvalidateTickables(); 698bf80f4bSopenharmony_ci SetTarget({}, {}); 708bf80f4bSopenharmony_ci observer_.reset(); 718bf80f4bSopenharmony_ci} 728bf80f4bSopenharmony_ci 738bf80f4bSopenharmony_cibool StartableObjectController::SetStartableQueueId( 748bf80f4bSopenharmony_ci const BASE_NS::Uid& startStartableQueueId, const BASE_NS::Uid& stopStartableQueueId) 758bf80f4bSopenharmony_ci{ 768bf80f4bSopenharmony_ci startQueueId_ = startStartableQueueId; 778bf80f4bSopenharmony_ci stopQueueId_ = stopStartableQueueId; 788bf80f4bSopenharmony_ci return true; 798bf80f4bSopenharmony_ci} 808bf80f4bSopenharmony_ci 818bf80f4bSopenharmony_civoid StartableObjectController::SetTarget(const IObject::Ptr& hierarchyRoot, HierarchyChangeModeValue mode) 828bf80f4bSopenharmony_ci{ 838bf80f4bSopenharmony_ci if (!observer_) { 848bf80f4bSopenharmony_ci return; 858bf80f4bSopenharmony_ci } 868bf80f4bSopenharmony_ci InvalidateTickables(); 878bf80f4bSopenharmony_ci target_ = hierarchyRoot; 888bf80f4bSopenharmony_ci bool automatic = META_ACCESS_PROPERTY_VALUE(StartBehavior) == StartBehavior::AUTOMATIC; 898bf80f4bSopenharmony_ci if (automatic && !hierarchyRoot) { 908bf80f4bSopenharmony_ci StopAll(ControlBehavior::CONTROL_AUTOMATIC); 918bf80f4bSopenharmony_ci } 928bf80f4bSopenharmony_ci observer_->SetTarget(hierarchyRoot, mode); 938bf80f4bSopenharmony_ci if (automatic && hierarchyRoot) { 948bf80f4bSopenharmony_ci StartAll(ControlBehavior::CONTROL_AUTOMATIC); 958bf80f4bSopenharmony_ci } 968bf80f4bSopenharmony_ci} 978bf80f4bSopenharmony_ci 988bf80f4bSopenharmony_ciIObject::Ptr StartableObjectController::GetTarget() const 998bf80f4bSopenharmony_ci{ 1008bf80f4bSopenharmony_ci return observer_->GetTarget(); 1018bf80f4bSopenharmony_ci} 1028bf80f4bSopenharmony_ci 1038bf80f4bSopenharmony_ciBASE_NS::vector<IObject::Ptr> StartableObjectController::GetAllObserved() const 1048bf80f4bSopenharmony_ci{ 1058bf80f4bSopenharmony_ci return observer_->GetAllObserved(); 1068bf80f4bSopenharmony_ci} 1078bf80f4bSopenharmony_ci 1088bf80f4bSopenharmony_cibool StartableObjectController::StartAll(ControlBehavior behavior) 1098bf80f4bSopenharmony_ci{ 1108bf80f4bSopenharmony_ci if (const auto root = target_.lock()) { 1118bf80f4bSopenharmony_ci return AddOperation({ StartableOperation::START, target_ }, startQueueId_); 1128bf80f4bSopenharmony_ci } 1138bf80f4bSopenharmony_ci return false; 1148bf80f4bSopenharmony_ci} 1158bf80f4bSopenharmony_ci 1168bf80f4bSopenharmony_cibool StartableObjectController::StopAll(ControlBehavior behavior) 1178bf80f4bSopenharmony_ci{ 1188bf80f4bSopenharmony_ci if (auto root = target_.lock()) { 1198bf80f4bSopenharmony_ci return AddOperation({ StartableOperation::STOP, target_ }, stopQueueId_); 1208bf80f4bSopenharmony_ci } 1218bf80f4bSopenharmony_ci return false; 1228bf80f4bSopenharmony_ci} 1238bf80f4bSopenharmony_ci 1248bf80f4bSopenharmony_citemplate<class T, class Callback> 1258bf80f4bSopenharmony_civoid IterateChildren(const BASE_NS::vector<T>& children, bool reverse, Callback&& callback) 1268bf80f4bSopenharmony_ci{ 1278bf80f4bSopenharmony_ci if (reverse) { 1288bf80f4bSopenharmony_ci for (auto it = children.rbegin(); it != children.rend(); ++it) { 1298bf80f4bSopenharmony_ci callback(*it); 1308bf80f4bSopenharmony_ci } 1318bf80f4bSopenharmony_ci } else { 1328bf80f4bSopenharmony_ci for (auto&& child : children) { 1338bf80f4bSopenharmony_ci callback(child); 1348bf80f4bSopenharmony_ci } 1358bf80f4bSopenharmony_ci } 1368bf80f4bSopenharmony_ci} 1378bf80f4bSopenharmony_ci 1388bf80f4bSopenharmony_citemplate<class Callback> 1398bf80f4bSopenharmony_civoid IterateHierarchy(const IObject::Ptr& root, bool reverse, Callback&& callback) 1408bf80f4bSopenharmony_ci{ 1418bf80f4bSopenharmony_ci if (const auto container = interface_cast<IContainer>(root)) { 1428bf80f4bSopenharmony_ci IterateChildren(container->GetAll(), reverse, callback); 1438bf80f4bSopenharmony_ci } 1448bf80f4bSopenharmony_ci if (const auto content = interface_cast<IContent>(root)) { 1458bf80f4bSopenharmony_ci if (auto object = GetValue(content->Content())) { 1468bf80f4bSopenharmony_ci callback(object); 1478bf80f4bSopenharmony_ci } 1488bf80f4bSopenharmony_ci } 1498bf80f4bSopenharmony_ci} 1508bf80f4bSopenharmony_ci 1518bf80f4bSopenharmony_citemplate<class ObjectType, class Callback> 1528bf80f4bSopenharmony_civoid IterateAttachments(const IObject::Ptr& object, bool reverse, Callback&& callback) 1538bf80f4bSopenharmony_ci{ 1548bf80f4bSopenharmony_ci if (const auto attach = interface_cast<IAttach>(object)) { 1558bf80f4bSopenharmony_ci if (auto container = attach->GetAttachmentContainer(false)) { 1568bf80f4bSopenharmony_ci IterateChildren(container->GetAll<ObjectType>(), reverse, BASE_NS::forward<Callback>(callback)); 1578bf80f4bSopenharmony_ci } 1588bf80f4bSopenharmony_ci } 1598bf80f4bSopenharmony_ci} 1608bf80f4bSopenharmony_ci 1618bf80f4bSopenharmony_citemplate<class Callback> 1628bf80f4bSopenharmony_civoid IterateStartables(const IObject::Ptr& object, bool reverse, Callback&& callback) 1638bf80f4bSopenharmony_ci{ 1648bf80f4bSopenharmony_ci IterateAttachments<IStartable, Callback>(object, reverse, BASE_NS::forward<Callback>(callback)); 1658bf80f4bSopenharmony_ci} 1668bf80f4bSopenharmony_ci 1678bf80f4bSopenharmony_citemplate<class Callback> 1688bf80f4bSopenharmony_civoid IterateTickables(const IObject::Ptr& object, TraversalType order, Callback&& callback) 1698bf80f4bSopenharmony_ci{ 1708bf80f4bSopenharmony_ci if (!object) { 1718bf80f4bSopenharmony_ci return; 1728bf80f4bSopenharmony_ci } 1738bf80f4bSopenharmony_ci bool rootFirst = order != TraversalType::DEPTH_FIRST_POST_ORDER; 1748bf80f4bSopenharmony_ci if (rootFirst) { 1758bf80f4bSopenharmony_ci IterateAttachments<ITickable, Callback>(object, false, BASE_NS::forward<Callback>(callback)); 1768bf80f4bSopenharmony_ci } 1778bf80f4bSopenharmony_ci IterateShared( 1788bf80f4bSopenharmony_ci object, 1798bf80f4bSopenharmony_ci [&callback](const IObject::Ptr& object) { 1808bf80f4bSopenharmony_ci IterateAttachments<ITickable, Callback>(object, false, callback); 1818bf80f4bSopenharmony_ci return true; 1828bf80f4bSopenharmony_ci }, 1838bf80f4bSopenharmony_ci order); 1848bf80f4bSopenharmony_ci if (!rootFirst) { 1858bf80f4bSopenharmony_ci IterateAttachments<ITickable, Callback>(object, false, BASE_NS::forward<Callback>(callback)); 1868bf80f4bSopenharmony_ci } 1878bf80f4bSopenharmony_ci} 1888bf80f4bSopenharmony_ci 1898bf80f4bSopenharmony_civoid StartableObjectController::HierarchyChanged(const HierarchyChangedInfo& info) 1908bf80f4bSopenharmony_ci{ 1918bf80f4bSopenharmony_ci if (info.change == HierarchyChangeType::ADDED || info.change == HierarchyChangeType::REMOVING || 1928bf80f4bSopenharmony_ci info.change == HierarchyChangeType::MOVED) { 1938bf80f4bSopenharmony_ci // Any hierarchy change (add/remove/move) invalidates the tick order 1948bf80f4bSopenharmony_ci InvalidateTickables(); 1958bf80f4bSopenharmony_ci if (info.change == HierarchyChangeType::ADDED) { 1968bf80f4bSopenharmony_ci AddOperation({ StartableOperation::START, info.object }, startQueueId_); 1978bf80f4bSopenharmony_ci } else if (info.change == HierarchyChangeType::REMOVING) { 1988bf80f4bSopenharmony_ci AddOperation({ StartableOperation::STOP, info.object }, stopQueueId_); 1998bf80f4bSopenharmony_ci } 2008bf80f4bSopenharmony_ci } 2018bf80f4bSopenharmony_ci} 2028bf80f4bSopenharmony_ci 2038bf80f4bSopenharmony_ciBASE_NS::vector<IStartable::Ptr> StartableObjectController::GetAllStartables() const 2048bf80f4bSopenharmony_ci{ 2058bf80f4bSopenharmony_ci BASE_NS::vector<IStartable::Ptr> startables; 2068bf80f4bSopenharmony_ci auto add = [&startables](const IStartable::Ptr& startable) { startables.push_back(startable); }; 2078bf80f4bSopenharmony_ci if (const auto root = target_.lock()) { 2088bf80f4bSopenharmony_ci IterateStartables(root, false, add); 2098bf80f4bSopenharmony_ci IterateShared( 2108bf80f4bSopenharmony_ci root, 2118bf80f4bSopenharmony_ci [&add](const IObject::Ptr& object) { 2128bf80f4bSopenharmony_ci IterateStartables(object, false, add); 2138bf80f4bSopenharmony_ci return true; 2148bf80f4bSopenharmony_ci }, 2158bf80f4bSopenharmony_ci TraversalType::DEPTH_FIRST_POST_ORDER); 2168bf80f4bSopenharmony_ci } 2178bf80f4bSopenharmony_ci return startables; 2188bf80f4bSopenharmony_ci} 2198bf80f4bSopenharmony_ci 2208bf80f4bSopenharmony_civoid StartableObjectController::StartHierarchy(const IObject::Ptr& root, ControlBehavior behavior) 2218bf80f4bSopenharmony_ci{ 2228bf80f4bSopenharmony_ci const auto traversal = META_ACCESS_PROPERTY_VALUE(TraversalType); 2238bf80f4bSopenharmony_ci if (traversal != TraversalType::DEPTH_FIRST_POST_ORDER && traversal != TraversalType::FULL_HIERARCHY) { 2248bf80f4bSopenharmony_ci CORE_LOG_E("Only DEPTH_FIRST_POST_ORDER is supported"); 2258bf80f4bSopenharmony_ci } 2268bf80f4bSopenharmony_ci 2278bf80f4bSopenharmony_ci if (!root) { 2288bf80f4bSopenharmony_ci return; 2298bf80f4bSopenharmony_ci } 2308bf80f4bSopenharmony_ci 2318bf80f4bSopenharmony_ci IterateHierarchy(root, false, [this, behavior](const IObject::Ptr& object) { StartHierarchy(object, behavior); }); 2328bf80f4bSopenharmony_ci 2338bf80f4bSopenharmony_ci // Don't traverse hierarchy for attachments 2348bf80f4bSopenharmony_ci IterateStartables( 2358bf80f4bSopenharmony_ci root, false, [this, behavior](const IStartable::Ptr& startable) { StartStartable(startable.get(), behavior); }); 2368bf80f4bSopenharmony_ci 2378bf80f4bSopenharmony_ci StartStartable(interface_cast<IStartable>(root), behavior); 2388bf80f4bSopenharmony_ci} 2398bf80f4bSopenharmony_ci 2408bf80f4bSopenharmony_civoid StartableObjectController::StartStartable(IStartable* const startable, ControlBehavior behavior) 2418bf80f4bSopenharmony_ci{ 2428bf80f4bSopenharmony_ci if (startable) { 2438bf80f4bSopenharmony_ci const auto state = GetValue(startable->StartableState()); 2448bf80f4bSopenharmony_ci if (state == StartableState::ATTACHED) { 2458bf80f4bSopenharmony_ci const auto mode = GetValue(startable->StartableMode()); 2468bf80f4bSopenharmony_ci if (behavior == ControlBehavior::CONTROL_ALL || mode == StartBehavior::AUTOMATIC) { 2478bf80f4bSopenharmony_ci startable->Start(); 2488bf80f4bSopenharmony_ci } 2498bf80f4bSopenharmony_ci } 2508bf80f4bSopenharmony_ci } 2518bf80f4bSopenharmony_ci} 2528bf80f4bSopenharmony_ci 2538bf80f4bSopenharmony_civoid StartableObjectController::StopHierarchy(const IObject::Ptr& root, ControlBehavior behavior) 2548bf80f4bSopenharmony_ci{ 2558bf80f4bSopenharmony_ci const auto traversal = META_ACCESS_PROPERTY_VALUE(TraversalType); 2568bf80f4bSopenharmony_ci if (traversal != TraversalType::DEPTH_FIRST_POST_ORDER && traversal != TraversalType::FULL_HIERARCHY) { 2578bf80f4bSopenharmony_ci CORE_LOG_E("Only DEPTH_FIRST_POST_ORDER is supported"); 2588bf80f4bSopenharmony_ci } 2598bf80f4bSopenharmony_ci if (!root) { 2608bf80f4bSopenharmony_ci return; 2618bf80f4bSopenharmony_ci } 2628bf80f4bSopenharmony_ci 2638bf80f4bSopenharmony_ci StopStartable(interface_cast<IStartable>(root), behavior); 2648bf80f4bSopenharmony_ci 2658bf80f4bSopenharmony_ci IterateStartables( 2668bf80f4bSopenharmony_ci root, true, [this, behavior](const IStartable::Ptr& startable) { StopStartable(startable.get(), behavior); }); 2678bf80f4bSopenharmony_ci 2688bf80f4bSopenharmony_ci IterateHierarchy(root, true, [this, behavior](const IObject::Ptr& object) { StopHierarchy(object, behavior); }); 2698bf80f4bSopenharmony_ci} 2708bf80f4bSopenharmony_ci 2718bf80f4bSopenharmony_civoid StartableObjectController::StopStartable(IStartable* const startable, ControlBehavior behavior) 2728bf80f4bSopenharmony_ci{ 2738bf80f4bSopenharmony_ci if (startable) { 2748bf80f4bSopenharmony_ci const auto state = GetValue(startable->StartableState()); 2758bf80f4bSopenharmony_ci if (state == StartableState::STARTED) { 2768bf80f4bSopenharmony_ci const auto mode = GetValue(startable->StartableMode()); 2778bf80f4bSopenharmony_ci if (behavior == ControlBehavior::CONTROL_ALL || mode == StartBehavior::AUTOMATIC) { 2788bf80f4bSopenharmony_ci startable->Stop(); 2798bf80f4bSopenharmony_ci } 2808bf80f4bSopenharmony_ci } 2818bf80f4bSopenharmony_ci } 2828bf80f4bSopenharmony_ci} 2838bf80f4bSopenharmony_ci 2848bf80f4bSopenharmony_cibool StartableObjectController::HasTasks(const BASE_NS::Uid& queueId) const 2858bf80f4bSopenharmony_ci{ 2868bf80f4bSopenharmony_ci std::shared_lock lock(mutex_); 2878bf80f4bSopenharmony_ci if (auto it = operations_.find(queueId); it != operations_.end()) { 2888bf80f4bSopenharmony_ci return !it->second.empty(); 2898bf80f4bSopenharmony_ci } 2908bf80f4bSopenharmony_ci return false; 2918bf80f4bSopenharmony_ci} 2928bf80f4bSopenharmony_ci 2938bf80f4bSopenharmony_civoid StartableObjectController::RunTasks(const BASE_NS::Uid& queueId) 2948bf80f4bSopenharmony_ci{ 2958bf80f4bSopenharmony_ci BASE_NS::vector<StartableOperation> operations; 2968bf80f4bSopenharmony_ci { 2978bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 2988bf80f4bSopenharmony_ci // Take tasks for the given queue id 2998bf80f4bSopenharmony_ci if (auto it = operations_.find(queueId); it != operations_.end()) { 3008bf80f4bSopenharmony_ci operations.swap(it->second); 3018bf80f4bSopenharmony_ci } 3028bf80f4bSopenharmony_ci } 3038bf80f4bSopenharmony_ci for (auto&& op : operations) { 3048bf80f4bSopenharmony_ci // This may potentially end up calling Start/StopHierarchy several times 3058bf80f4bSopenharmony_ci // for the same subtrees, but we will accept that. Start/Stop will only 3068bf80f4bSopenharmony_ci // be called once since the functions check for current state. 3078bf80f4bSopenharmony_ci if (auto root = op.root_.lock()) { 3088bf80f4bSopenharmony_ci switch (op.operation_) { 3098bf80f4bSopenharmony_ci case StartableOperation::START: 3108bf80f4bSopenharmony_ci ++executingStart_; 3118bf80f4bSopenharmony_ci StartHierarchy(root, ControlBehavior::CONTROL_AUTOMATIC); 3128bf80f4bSopenharmony_ci --executingStart_; 3138bf80f4bSopenharmony_ci break; 3148bf80f4bSopenharmony_ci case StartableOperation::STOP: 3158bf80f4bSopenharmony_ci StopHierarchy(root, ControlBehavior::CONTROL_AUTOMATIC); 3168bf80f4bSopenharmony_ci break; 3178bf80f4bSopenharmony_ci default: 3188bf80f4bSopenharmony_ci break; 3198bf80f4bSopenharmony_ci } 3208bf80f4bSopenharmony_ci } 3218bf80f4bSopenharmony_ci } 3228bf80f4bSopenharmony_ci} 3238bf80f4bSopenharmony_ci 3248bf80f4bSopenharmony_cibool StartableObjectController::ProcessOps(const BASE_NS::Uid& queueId) 3258bf80f4bSopenharmony_ci{ 3268bf80f4bSopenharmony_ci if (!HasTasks(queueId)) { 3278bf80f4bSopenharmony_ci // No tasks for the given queue, bail out 3288bf80f4bSopenharmony_ci return true; 3298bf80f4bSopenharmony_ci } 3308bf80f4bSopenharmony_ci 3318bf80f4bSopenharmony_ci auto task = [queueId, internal = IStartableObjectControllerInternal::WeakPtr { 3328bf80f4bSopenharmony_ci GetSelf<IStartableObjectControllerInternal>() }]() { 3338bf80f4bSopenharmony_ci if (auto me = internal.lock()) { 3348bf80f4bSopenharmony_ci me->RunTasks(queueId); 3358bf80f4bSopenharmony_ci } 3368bf80f4bSopenharmony_ci }; 3378bf80f4bSopenharmony_ci 3388bf80f4bSopenharmony_ci if (queueId != BASE_NS::Uid {} && !executingStart_) { 3398bf80f4bSopenharmony_ci if (auto queue = GetTaskQueueRegistry().GetTaskQueue(queueId)) { 3408bf80f4bSopenharmony_ci queue->AddWaitableTask(CreateWaitableTask(BASE_NS::move(task))); 3418bf80f4bSopenharmony_ci return true; 3428bf80f4bSopenharmony_ci } 3438bf80f4bSopenharmony_ci CORE_LOG_W("Cannot get task queue '%s'. Running the task synchronously.", BASE_NS::to_string(queueId).c_str()); 3448bf80f4bSopenharmony_ci } 3458bf80f4bSopenharmony_ci // Just run the task immediately if we don't have a queue to defer it to 3468bf80f4bSopenharmony_ci task(); 3478bf80f4bSopenharmony_ci return true; 3488bf80f4bSopenharmony_ci} 3498bf80f4bSopenharmony_ci 3508bf80f4bSopenharmony_cibool StartableObjectController::AddOperation(StartableOperation&& operation, const BASE_NS::Uid& queueId) 3518bf80f4bSopenharmony_ci{ 3528bf80f4bSopenharmony_ci auto object = operation.root_.lock(); 3538bf80f4bSopenharmony_ci if (!object) { 3548bf80f4bSopenharmony_ci return false; 3558bf80f4bSopenharmony_ci } 3568bf80f4bSopenharmony_ci // Note that queueId may be {}, but it is still a valid key for our queue map 3578bf80f4bSopenharmony_ci { 3588bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 3598bf80f4bSopenharmony_ci auto& ops = operations_[queueId]; 3608bf80f4bSopenharmony_ci for (auto it = ops.begin(); it != ops.end(); ++it) { 3618bf80f4bSopenharmony_ci // If we already have an operation in queue for a given object, cancel the existing operation 3628bf80f4bSopenharmony_ci // and just add the new one 3638bf80f4bSopenharmony_ci if ((*it).root_.lock() == object) { 3648bf80f4bSopenharmony_ci ops.erase(it); 3658bf80f4bSopenharmony_ci break; 3668bf80f4bSopenharmony_ci } 3678bf80f4bSopenharmony_ci } 3688bf80f4bSopenharmony_ci ops.emplace_back(BASE_NS::move(operation)); 3698bf80f4bSopenharmony_ci } 3708bf80f4bSopenharmony_ci return ProcessOps(queueId); 3718bf80f4bSopenharmony_ci} 3728bf80f4bSopenharmony_ci 3738bf80f4bSopenharmony_civoid StartableObjectController::InvalidateTickables() 3748bf80f4bSopenharmony_ci{ 3758bf80f4bSopenharmony_ci std::unique_lock lock(mutex_); 3768bf80f4bSopenharmony_ci tickables_.clear(); 3778bf80f4bSopenharmony_ci tickablesValid_ = false; 3788bf80f4bSopenharmony_ci} 3798bf80f4bSopenharmony_ci 3808bf80f4bSopenharmony_ciBASE_NS::vector<ITickable::Ptr> StartableObjectController::GetTickables() const 3818bf80f4bSopenharmony_ci{ 3828bf80f4bSopenharmony_ci BASE_NS::vector<ITickable::WeakPtr> weaks; 3838bf80f4bSopenharmony_ci { 3848bf80f4bSopenharmony_ci std::unique_lock lock(tickMutex_); 3858bf80f4bSopenharmony_ci if (!tickablesValid_) { 3868bf80f4bSopenharmony_ci auto add = [this](const ITickable::Ptr& tickable) { tickables_.push_back(tickable); }; 3878bf80f4bSopenharmony_ci IterateTickables(target_.lock(), META_ACCESS_PROPERTY_VALUE(TickOrder), add); 3888bf80f4bSopenharmony_ci tickablesValid_ = true; 3898bf80f4bSopenharmony_ci } 3908bf80f4bSopenharmony_ci weaks = tickables_; 3918bf80f4bSopenharmony_ci } 3928bf80f4bSopenharmony_ci BASE_NS::vector<ITickable::Ptr> tickables; 3938bf80f4bSopenharmony_ci tickables.reserve(weaks.size()); 3948bf80f4bSopenharmony_ci for (auto&& t : weaks) { 3958bf80f4bSopenharmony_ci if (auto tick = t.lock()) { 3968bf80f4bSopenharmony_ci tickables.emplace_back(BASE_NS::move(tick)); 3978bf80f4bSopenharmony_ci } 3988bf80f4bSopenharmony_ci } 3998bf80f4bSopenharmony_ci return tickables; 4008bf80f4bSopenharmony_ci} 4018bf80f4bSopenharmony_ci 4028bf80f4bSopenharmony_civoid StartableObjectController::UpdateTicker() 4038bf80f4bSopenharmony_ci{ 4048bf80f4bSopenharmony_ci auto queue = tickQueueId_ != BASE_NS::Uid {} ? META_NS::GetTaskQueueRegistry().GetTaskQueue(tickQueueId_) 4058bf80f4bSopenharmony_ci : defaultTickerQueue_; 4068bf80f4bSopenharmony_ci if (tickerQueue_ && tickerToken_) { 4078bf80f4bSopenharmony_ci tickerQueue_->CancelTask(tickerToken_); 4088bf80f4bSopenharmony_ci tickerToken_ = {}; 4098bf80f4bSopenharmony_ci } 4108bf80f4bSopenharmony_ci tickerQueue_ = queue; 4118bf80f4bSopenharmony_ci if (const auto interval = META_ACCESS_PROPERTY_VALUE(TickInterval); interval != TimeSpan::Infinite()) { 4128bf80f4bSopenharmony_ci if (tickerQueue_) { 4138bf80f4bSopenharmony_ci tickerToken_ = tickerQueue_->AddTask(tickerTask_, interval); 4148bf80f4bSopenharmony_ci } else { 4158bf80f4bSopenharmony_ci CORE_LOG_E("Invalid queue given for running ITickables: %s", BASE_NS::to_string(tickQueueId_).c_str()); 4168bf80f4bSopenharmony_ci } 4178bf80f4bSopenharmony_ci } 4188bf80f4bSopenharmony_ci} 4198bf80f4bSopenharmony_ci 4208bf80f4bSopenharmony_cibool StartableObjectController::SetTickableQueueuId(const BASE_NS::Uid& queueId) 4218bf80f4bSopenharmony_ci{ 4228bf80f4bSopenharmony_ci if (queueId != tickQueueId_) { 4238bf80f4bSopenharmony_ci tickQueueId_ = queueId; 4248bf80f4bSopenharmony_ci UpdateTicker(); 4258bf80f4bSopenharmony_ci } 4268bf80f4bSopenharmony_ci return true; 4278bf80f4bSopenharmony_ci} 4288bf80f4bSopenharmony_ci 4298bf80f4bSopenharmony_civoid StartableObjectController::TickAll(const TimeSpan& time) 4308bf80f4bSopenharmony_ci{ 4318bf80f4bSopenharmony_ci const auto tickables = GetTickables(); 4328bf80f4bSopenharmony_ci if (!tickables.empty()) { 4338bf80f4bSopenharmony_ci const auto sinceLast = lastTick_ != TimeSpan::Infinite() ? time - lastTick_ : TimeSpan::Zero(); 4348bf80f4bSopenharmony_ci for (auto&& tickable : tickables) { 4358bf80f4bSopenharmony_ci bool shouldTick = true; 4368bf80f4bSopenharmony_ci if (const auto st = interface_cast<IStartable>(tickable)) { 4378bf80f4bSopenharmony_ci shouldTick = GetValue(st->StartableState()) == StartableState::STARTED; 4388bf80f4bSopenharmony_ci } 4398bf80f4bSopenharmony_ci if (shouldTick) { 4408bf80f4bSopenharmony_ci tickable->Tick(time, sinceLast); 4418bf80f4bSopenharmony_ci } 4428bf80f4bSopenharmony_ci } 4438bf80f4bSopenharmony_ci } 4448bf80f4bSopenharmony_ci lastTick_ = time; 4458bf80f4bSopenharmony_ci} 4468bf80f4bSopenharmony_ci 4478bf80f4bSopenharmony_ciMETA_END_NAMESPACE() 448