diff --git a/adapter/ohos/osal/system_properties.cpp b/adapter/ohos/osal/system_properties.cpp index a7638c611e01feaf6ab7d1e0f4f1b7bf88f8c356..c81fdaf9963fe45c1238f7e3f71a2ef4e04500ee 100644 --- a/adapter/ohos/osal/system_properties.cpp +++ b/adapter/ohos/osal/system_properties.cpp @@ -48,6 +48,7 @@ constexpr char ENABLE_DEBUG_BOUNDARY_KEY[] = "persist.ace.debug.boundary.enabled constexpr char ENABLE_DOWNLOAD_BY_NETSTACK_KEY[] = "persist.ace.download.netstack.enabled"; constexpr char ENABLE_RECYCLE_IMAGE_KEY[] = "persist.ace.recycle.image.enabled"; constexpr char ENABLE_DEBUG_OFFSET_LOG_KEY[] = "persist.ace.scrollable.log.enabled"; +constexpr char ENABLE_DEBUG_THREAD_SAFE_NODE_KEY[] = "persist.ace.debug.thread_safe_node.enabled"; constexpr char ANIMATION_SCALE_KEY[] = "persist.sys.arkui.animationscale"; constexpr char CUSTOM_TITLE_KEY[] = "persist.sys.arkui.customtitle"; constexpr char DISTRIBUTE_ENGINE_BUNDLE_NAME[] = "atomic.service.distribute.engine.bundle.name"; @@ -500,6 +501,11 @@ std::string InitSysDeviceType() return SystemProperties::INVALID_PARAM; } +bool IsDebugThreadSafeNodeEnabled() +{ + return system::GetBoolParameter(ENABLE_DEBUG_THREAD_SAFE_NODE_KEY, false); +} + std::atomic SystemProperties::asyncInitializeEnabled_(IsAsyncInitializeEnabled()); bool SystemProperties::svgTraceEnable_ = IsSvgTraceEnabled(); bool SystemProperties::developerModeOn_ = IsDeveloperModeOn(); @@ -584,6 +590,7 @@ bool SystemProperties::taskPriorityAdjustmentEnable_ = IsTaskPriorityAdjustmentE int32_t SystemProperties::dragDropFrameworkStatus_ = ReadDragDropFrameworkStatus(); int32_t SystemProperties::touchAccelarate_ = ReadTouchAccelarateMode(); bool SystemProperties::pageTransitionFrzEnabled_ = false; +bool SystemProperties::debugThreadSafeNodeEnable_ = IsDebugThreadSafeNodeEnabled(); bool SystemProperties::IsOpIncEnable() { diff --git a/adapter/preview/osal/system_properties.cpp b/adapter/preview/osal/system_properties.cpp index f25b70113506c96d0e57ebc43fbfe0f967e188c8..3c2bc615d5f61ce69a6b94d7e64951b66eb8049f 100644 --- a/adapter/preview/osal/system_properties.cpp +++ b/adapter/preview/osal/system_properties.cpp @@ -118,6 +118,7 @@ bool SystemProperties::taskPriorityAdjustmentEnable_ = false; int32_t SystemProperties::dragDropFrameworkStatus_ = 0; int32_t SystemProperties::touchAccelarate_ = 0; bool SystemProperties::pageTransitionFrzEnabled_ = false; +bool SystemProperties::debugThreadSafeNodeEnable_ = false; bool SystemProperties::IsOpIncEnable() { diff --git a/frameworks/base/utils/system_properties.h b/frameworks/base/utils/system_properties.h index 4bc8e72d3f60181f19280e266049049da8b1391a..374d8e2f47c76d3b79798a29d552589da0ec6578 100644 --- a/frameworks/base/utils/system_properties.h +++ b/frameworks/base/utils/system_properties.h @@ -701,6 +701,11 @@ public: static bool IsPageTransitionFreeze(); + static bool GetDebugThreadSafeNodeEnabled() + { + return debugThreadSafeNodeEnable_; + } + private: static bool opincEnabled_; static bool developerModeOn_; @@ -786,6 +791,7 @@ private: static int32_t dragDropFrameworkStatus_; static int32_t touchAccelarate_; static bool pageTransitionFrzEnabled_; + static bool debugThreadSafeNodeEnable_; }; } // namespace OHOS::Ace diff --git a/frameworks/core/common/multi_thread_build_manager.cpp b/frameworks/core/common/multi_thread_build_manager.cpp index d53c5147d4a017c6148ed63169612e7068aa8aa1..ebdb0c2dd7cae621dce83265ff8b5c0086fd1a28 100644 --- a/frameworks/core/common/multi_thread_build_manager.cpp +++ b/frameworks/core/common/multi_thread_build_manager.cpp @@ -21,6 +21,7 @@ #include "base/log/log_wrapper.h" #include "base/log/ace_trace.h" #include "base/memory/referenced.h" +#include "base/utils/system_properties.h" #include "core/common/container.h" #include "core/pipeline_ng/pipeline_context.h" @@ -32,7 +33,7 @@ constexpr uint32_t ASYNC_UITASK_QOS = 5; std::unique_ptr asyncUITaskQueue = nullptr; #endif } -thread_local bool MultiThreadBuildManager::isFreeNodeScope_ = false; +thread_local bool MultiThreadBuildManager::isThreadSafeNodeScope_ = false; thread_local bool MultiThreadBuildManager::isUIThread_ = false; MultiThreadBuildManager& MultiThreadBuildManager::GetInstance() @@ -79,44 +80,31 @@ bool MultiThreadBuildManager::CheckNodeOnValidThread(NG::UINode* node) TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "CheckNodeOnValidThread failed. node is nullptr"); return false; } - if (!node->IsFreeState() && !MultiThreadBuildManager::IsOnUIThread()) { + if (!node->IsFree() && !MultiThreadBuildManager::IsOnUIThread()) { TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "CheckNodeOnValidThread failed. unfree node not run on main thread"); return false; } return true; } -void MultiThreadBuildManager::SetIsFreeNodeScope(bool isFreeNodeScope) +void MultiThreadBuildManager::SetIsThreadSafeNodeScope(bool isThreadSafeNodeScope) { - isFreeNodeScope_ = isFreeNodeScope; + isThreadSafeNodeScope_ = isThreadSafeNodeScope; } -bool MultiThreadBuildManager::IsFreeNodeScope() +bool MultiThreadBuildManager::IsThreadSafeNodeScope() { - return isFreeNodeScope_; -} - -void MultiThreadBuildManager::TryExecuteUnSafeTask(NG::UINode* node, std::function&& task) -{ - if (node->IsFreeState()) { - node->PostAfterAttachMainTreeTask(std::move(task)); - } else if (task) { - task(); - } -} - -bool MultiThreadBuildManager::TryPostUnSafeTask(NG::UINode* node, std::function&& task) -{ - if (node->IsFreeState()) { - node->PostAfterAttachMainTreeTask(std::move(task)); - return true; - } - return false; + return isThreadSafeNodeScope_ || SystemProperties::GetDebugThreadSafeNodeEnabled(); } bool MultiThreadBuildManager::PostAsyncUITask(int32_t contextId, std::function&& asyncUITask, std::function&& onFinishTask) { + ContainerScope scope(contextId); + auto container = Container::Current(); + CHECK_NULL_RETURN(container, false); + auto taskExecutor = container->GetTaskExecutor(); + CHECK_NULL_RETURN(taskExecutor, false); #ifdef FFRT_SUPPORT if (!asyncUITaskQueue) { return false; @@ -136,11 +124,6 @@ bool MultiThreadBuildManager::PostAsyncUITask(int32_t contextId, std::functionGetTaskExecutor(); - CHECK_NULL_RETURN(taskExecutor, false); return taskExecutor->PostTask([contextId, asyncUITask = std::move(asyncUITask), onFinishTask = std::move(onFinishTask)]() { ContainerScope scope(contextId); diff --git a/frameworks/core/common/multi_thread_build_manager.h b/frameworks/core/common/multi_thread_build_manager.h index 10f64d859e61d4e9c3591fdc0285f34f196356f3..d34c61a45da06332262f39c1359b081d6a53f320 100644 --- a/frameworks/core/common/multi_thread_build_manager.h +++ b/frameworks/core/common/multi_thread_build_manager.h @@ -32,10 +32,8 @@ public: static bool IsOnUIThread(); static bool CheckOnUIThread(); static bool CheckNodeOnValidThread(NG::UINode* node); - static void SetIsFreeNodeScope(bool isFreeNodeScope); - static bool IsFreeNodeScope(); - static void TryExecuteUnSafeTask(NG::UINode* node, std::function&& task); - static bool TryPostUnSafeTask(NG::UINode* node, std::function&& task); + static void SetIsThreadSafeNodeScope(bool isThreadSafeNodeScope); + static bool IsThreadSafeNodeScope(); bool PostAsyncUITask(int32_t contextId, std::function&& asyncUITask, std::function&& onFinishTask); bool PostUITask(int32_t contextId, std::function&& uiTask); @@ -43,7 +41,7 @@ public: private: MultiThreadBuildManager(); void InitAsyncUITaskQueue(); - static thread_local bool isFreeNodeScope_; + static thread_local bool isThreadSafeNodeScope_; static thread_local bool isUIThread_; ACE_DISALLOW_COPY_AND_MOVE(MultiThreadBuildManager); }; diff --git a/frameworks/core/components_ng/base/frame_node.cpp b/frameworks/core/components_ng/base/frame_node.cpp index cea4ef9bcce8b02d4d0c3ac9b52fcf5b09cdf2a2..8a4bbf7aa3febba5f4010f263a544bfb3c8a7692 100644 --- a/frameworks/core/components_ng/base/frame_node.cpp +++ b/frameworks/core/components_ng/base/frame_node.cpp @@ -2384,7 +2384,7 @@ void FrameNode::UpdateLayoutConstraint(const MeasureProperty& calcLayoutConstrai layoutProperty_->UpdateCalcLayoutProperty(calcLayoutConstraint); } -void FrameNode::RebuildRenderContextTree() +void FrameNode::RebuildRenderContextTreeUnsafely() { if (!needSyncRenderTree_) { return; @@ -2421,6 +2421,19 @@ void FrameNode::RebuildRenderContextTree() needSyncRenderTree_ = false; } +void FrameNode::RebuildRenderContextTree() +{ + if (!IsFree()) { + RebuildRenderContextTreeUnsafely(); + } else { + PostAfterAttachMainTreeTask([weak = WeakClaim(this)]() { + auto host = weak.Upgrade(); + CHECK_NULL_VOID(host); + host->RebuildRenderContextTreeUnsafely(); + }); + } +} + void FrameNode::MarkModifyDoneUnsafely() { pattern_->OnModifyDone(); @@ -2468,7 +2481,7 @@ void FrameNode::MarkModifyDoneUnsafely() void FrameNode::MarkModifyDone() { - if (!IsFreeState()) { + if (!IsFree()) { MarkModifyDoneUnsafely(); } else { PostAfterAttachMainTreeTask([weak = WeakClaim(this)]() { @@ -2519,7 +2532,7 @@ void FrameNode::MarkDirtyNodeUnsafely(PropertyChangeFlag extraFlag) void FrameNode::MarkDirtyNode(PropertyChangeFlag extraFlag) { - if (!IsFreeState()) { + if (!IsFree()) { MarkDirtyNodeUnsafely(extraFlag); } else { PostAfterAttachMainTreeTask([weak = WeakClaim(this), extraFlag]() { @@ -2622,7 +2635,17 @@ void FrameNode::MarkNeedRender(bool isRenderBoundary) } isRenderDirtyMarked_ = true; if (isRenderBoundary) { - context->AddDirtyRenderNode(Claim(this)); + if (!IsFree()) { + context->AddDirtyRenderNode(Claim(this)); + } else { + PostAfterAttachMainTreeTask([weak = WeakClaim(this)]() { + auto frameNode = weak.Upgrade(); + CHECK_NULL_VOID(frameNode); + auto context = frameNode->GetContext(); + CHECK_NULL_VOID(context); + context->AddDirtyRenderNode(weak.Upgrade()); + }); + } return; } auto parent = GetAncestorNodeOfFrame(false); diff --git a/frameworks/core/components_ng/base/frame_node.h b/frameworks/core/components_ng/base/frame_node.h index 278286bd0a72f34c01b6953921b320ba176ce101..285f303404f534d36b6d895ceacbe166995eaadd 100644 --- a/frameworks/core/components_ng/base/frame_node.h +++ b/frameworks/core/components_ng/base/frame_node.h @@ -1346,6 +1346,7 @@ public: ScrollWindowAdapter* GetOrCreateScrollWindowAdapter(); void MarkModifyDoneUnsafely(); void MarkDirtyNodeUnsafely(PropertyChangeFlag extraFlag); + void RebuildRenderContextTreeUnsafely(); bool HasMultipleChild(); diff --git a/frameworks/core/components_ng/base/ui_node.cpp b/frameworks/core/components_ng/base/ui_node.cpp index bc7d57b136dc724fa7350673c2b22efe38c86b0f..f5d3b1c1733402f923acf2a29c98929683ff931a 100644 --- a/frameworks/core/components_ng/base/ui_node.cpp +++ b/frameworks/core/components_ng/base/ui_node.cpp @@ -30,9 +30,9 @@ const std::set UINode::layoutTags_ = { "Flex", "Stack", "Row", "Col UINode::UINode(const std::string& tag, int32_t nodeId, bool isRoot) : tag_(tag), nodeId_(nodeId), accessibilityId_(currentAccessibilityId_++), isRoot_(isRoot) { - if (MultiThreadBuildManager::IsFreeNodeScope()) { - isFreeNode_ = true; - isFreeState_ = true; + if (MultiThreadBuildManager::IsThreadSafeNodeScope()) { + isThreadSafeNode_ = true; + isFree_ = true; } if (AceChecker::IsPerformanceCheckEnabled()) { auto pos = EngineHelper::GetPositionOnJsCode(); @@ -74,6 +74,9 @@ UINode::~UINode() } else { ElementRegister::GetInstance()->RemoveItemSilently(nodeId_); } + if (isThreadSafeNode_) { + ElementRegister::GetInstance()->RemoveThreadSafeNode(nodeId_); + } if (propInspectorId_.has_value()) { ElementRegister::GetInstance()->RemoveFrameNodeByInspectorId(propInspectorId_.value_or(""), nodeId_); } @@ -91,7 +94,7 @@ UINode::~UINode() bool UINode::MaybeRelease() { - if (!isFreeNode_ || MultiThreadBuildManager::IsOnUIThread()) { + if (!isThreadSafeNode_ || MultiThreadBuildManager::IsOnUIThread()) { return true; } auto pipeline = GetContext(); @@ -789,8 +792,8 @@ void UINode::AttachToMainTree(bool recursive, PipelineContext* context) nodeStatus_ = NodeStatus::BUILDER_NODE_ON_MAINTREE; } isRemoving_ = false; - if (isFreeNode_) { - isFreeState_ = false; + if (isThreadSafeNode_) { + isFree_ = false; ElementRegister::GetInstance()->AddUINode(Claim(this)); ExecuteAfterAttachMainTreeTasks(); } @@ -848,13 +851,13 @@ void UINode::DetachFromMainTree(bool recursive, bool isRoot) for (const auto& child : children) { child->DetachFromMainTree(isRecursive, false); } - if (isFreeNode_) { + if (isThreadSafeNode_) { ElementRegister::GetInstance()->RemoveItemSilently(Claim(this)); - isFreeState_ = true; - if (isRoot && !IsFreeNodeTree()) { - // Remind developers that it is unsafe to operate node trees containing not free nodes on non UI threads + isFree_ = true; + if (isRoot && !IsThreadSafeNodeTree()) { + // Remind developers that it is unsafe to operate node tree contains not thread safe node on non UI thread TAG_LOGW(AceLogTag::ACE_NATIVE_NODE, - "CheckIsFreeNodeSubTree failed. free node: %{public}d contains not free node children", GetId()); + "CheckIsThreadSafeNodeTree failed. node: %{public}d contains not thread safe node children", GetId()); } } isTraversing_ = false; diff --git a/frameworks/core/components_ng/base/ui_node.h b/frameworks/core/components_ng/base/ui_node.h index 70d97cf764ebfecba2af380b9f05917891927bc9..6ebd422e6880c5ee551cfb0e0a51e499962aba77 100644 --- a/frameworks/core/components_ng/base/ui_node.h +++ b/frameworks/core/components_ng/base/ui_node.h @@ -922,27 +922,14 @@ public: return true; } - bool IsFreeNode() const + bool IsThreadSafeNode() const { - return isFreeNode_; + return isThreadSafeNode_; } - bool IsFreeState() const + bool IsFree() const { - return isFreeState_; - } - - bool IsFreeNodeTree() - { - if (!IsFreeNode()) { - return false; - } - for (const auto& child : GetChildren()) { - if (!child->IsFreeNodeTree()) { - return false; - } - } - return true; + return isFree_; } void PostAfterAttachMainTreeTask(std::function&& task) @@ -953,16 +940,6 @@ public: afterAttachMainTreeTasks_.emplace_back(std::move(task)); } - void ExecuteAfterAttachMainTreeTasks() - { - for (auto& task : afterAttachMainTreeTasks_) { - if (task) { - task(); - } - } - afterAttachMainTreeTasks_.clear(); - } - protected: std::list>& ModifyChildren() { @@ -1051,6 +1028,28 @@ private: void DoAddChild(std::list>::iterator& it, const RefPtr& child, bool silently = false, bool addDefaultTransition = false); bool CanAddChildWhenTopNodeIsModalUec(std::list>::iterator& curIter); + void ExecuteAfterAttachMainTreeTasks() + { + for (auto& task : afterAttachMainTreeTasks_) { + if (task) { + task(); + } + } + afterAttachMainTreeTasks_.clear(); + } + + bool IsThreadSafeNodeTree() + { + if (!IsThreadSafeNode()) { + return false; + } + for (const auto& child : GetChildren()) { + if (!child->IsThreadSafeNodeTree()) { + return false; + } + } + return true; + } virtual bool MaybeRelease() override; std::list> children_; @@ -1069,8 +1068,8 @@ private: int32_t themeScopeId_ = 0; bool isRoot_ = false; bool onMainTree_ = false; - bool isFreeNode_ = false; - bool isFreeState_ = false; + bool isThreadSafeNode_ = false; + bool isFree_ = false; // the thread safe node in free state can be operated by non UI threads std::vector> afterAttachMainTreeTasks_; bool removeSilently_ = true; bool isInDestroying_ = false; diff --git a/frameworks/core/components_ng/render/render_context.cpp b/frameworks/core/components_ng/render/render_context.cpp index bc80f5527ea6c91f57d3049426a663f0a9011c90..87f4f0a46ac08e360a51781c8af411fac311d70e 100644 --- a/frameworks/core/components_ng/render/render_context.cpp +++ b/frameworks/core/components_ng/render/render_context.cpp @@ -42,18 +42,32 @@ void RenderContext::SetRequestFrame(const std::function& requestFrame) requestFrame_ = requestFrame; } +void RenderContext::SetNeedRenderNode(RefPtr& node) const +{ + auto eventHub = node->GetEventHubOnly(); + if (node->GetInspectorId().has_value() || (eventHub && eventHub->HasNDKDrawCompletedCallback())) { + if (!node->IsFree()) { + auto pipeline = AceType::DynamicCast(PipelineBase::GetCurrentContext()); + CHECK_NULL_VOID(pipeline); + pipeline->SetNeedRenderNode(WeakPtr(node)); + } else { + node->PostAfterAttachMainTreeTask([weak = WeakPtr(node)]() { + auto pipeline = AceType::DynamicCast(PipelineBase::GetCurrentContext()); + CHECK_NULL_VOID(pipeline); + pipeline->SetNeedRenderNode(weak); + }); + } + } +} + + void RenderContext::RequestNextFrame() const { if (requestFrame_) { requestFrame_(); auto node = GetHost(); CHECK_NULL_VOID(node); - auto eventHub = node->GetEventHubOnly(); - if (node->GetInspectorId().has_value() || (eventHub && eventHub->HasNDKDrawCompletedCallback())) { - auto pipeline = AceType::DynamicCast(PipelineBase::GetCurrentContext()); - CHECK_NULL_VOID(pipeline); - pipeline->SetNeedRenderNode(WeakPtr(node)); - } + SetNeedRenderNode(node); } } diff --git a/frameworks/core/components_ng/render/render_context.h b/frameworks/core/components_ng/render/render_context.h index 5879c2a6db2df5129cc945c4653ea06d276a7e14..3a7f07d70615bf3139a6b7562dcab3763b428d2c 100644 --- a/frameworks/core/components_ng/render/render_context.h +++ b/frameworks/core/components_ng/render/render_context.h @@ -897,6 +897,7 @@ protected: virtual void OnAttractionEffectUpdate(const AttractionEffect& effect) {} private: + void SetNeedRenderNode(RefPtr& node) const; friend class ViewAbstract; friend class ViewAbstractModelStatic; std::function requestFrame_; diff --git a/frameworks/core/interfaces/arkoala/arkoala_api.h b/frameworks/core/interfaces/arkoala/arkoala_api.h index da3879ee20ecd9ff288dbc5b8b297cd42229fdbb..5e868bc5e51b2de3ff96dd32f0fdd008da58aa82 100644 --- a/frameworks/core/interfaces/arkoala/arkoala_api.h +++ b/frameworks/core/interfaces/arkoala/arkoala_api.h @@ -6173,7 +6173,7 @@ struct ArkUIBasicAPI { }; struct ArkUIMultiThreadManagerAPI { - void (*setIsFreeNodeScope)(ArkUI_Bool isFreeNodeScope); + void (*setIsThreadSafeNodeScope)(ArkUI_Bool isThreadSafeNodeScope); ArkUI_Bool (*checkNodeOnValidThread)(ArkUINodeHandle node); ArkUI_Bool (*checkOnUIThread)(); ArkUI_Int32 (*postAsyncUITask)(ArkUI_Int32 contextId, diff --git a/frameworks/core/interfaces/native/node/frame_node_modifier.cpp b/frameworks/core/interfaces/native/node/frame_node_modifier.cpp index e2078d16cd0247252b5399b6eba8a684c1c7e18a..0d24f29e75cd7b172dfe0a510fd4706cb367360e 100644 --- a/frameworks/core/interfaces/native/node/frame_node_modifier.cpp +++ b/frameworks/core/interfaces/native/node/frame_node_modifier.cpp @@ -119,7 +119,11 @@ void ClearChildrenInFrameNode(ArkUINodeHandle node) { auto* currentNode = reinterpret_cast(node); CHECK_NULL_VOID(currentNode); - currentNode->Clean(); + if (currentNode->IsFree()) { + currentNode->Clean(true); + } else { + currentNode->Clean(); + } currentNode->MarkNeedFrameFlushDirty(NG::PROPERTY_UPDATE_MEASURE); } diff --git a/frameworks/core/interfaces/native/node/node_api.cpp b/frameworks/core/interfaces/native/node/node_api.cpp index 9897e30681c3ba4a5bcabbd97eb780384e20db19..e7f169795746e31613b7fb48f868fdb497427a3f 100644 --- a/frameworks/core/interfaces/native/node/node_api.cpp +++ b/frameworks/core/interfaces/native/node/node_api.cpp @@ -1790,9 +1790,9 @@ ArkUI_Int32 PostFrameCallback(ArkUI_Int32 instanceId, void* userData, return ERROR_CODE_NO_ERROR; } -void SetIsFreeNodeScope(ArkUI_Bool isFreeNodeScope) +void SetIsThreadSafeNodeScope(ArkUI_Bool isThreadSafeNodeScope) { - MultiThreadBuildManager::SetIsFreeNodeScope(isFreeNodeScope); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(isThreadSafeNodeScope); } int32_t CheckNodeOnValidThread(ArkUINodeHandle node) @@ -1893,7 +1893,7 @@ const ArkUIBasicAPI* GetBasicAPI() const ArkUIMultiThreadManagerAPI* GetMultiThreadManagerAPI() { static const ArkUIMultiThreadManagerAPI multiThreadImpl = { - .setIsFreeNodeScope = SetIsFreeNodeScope, + .setIsThreadSafeNodeScope = SetIsThreadSafeNodeScope, .checkNodeOnValidThread = CheckNodeOnValidThread, .checkOnUIThread = CheckOnUIThread, .postAsyncUITask = PostAsyncUITask, diff --git a/frameworks/core/interfaces/native/node/node_common_modifier.cpp b/frameworks/core/interfaces/native/node/node_common_modifier.cpp index 7305eef4b152f95a732ec8ab802900f2303045e3..6e0905a2556f835970ae3842fa39be2ee6b49769 100644 --- a/frameworks/core/interfaces/native/node/node_common_modifier.cpp +++ b/frameworks/core/interfaces/native/node/node_common_modifier.cpp @@ -140,7 +140,7 @@ const std::vector DIRECTION_LIST = { }; constexpr int32_t DEFAULT_DURATION = 1000; -std::string g_strValue; +thread_local std::string g_strValue; BorderStyle ConvertBorderStyle(int32_t value) { diff --git a/frameworks/core/interfaces/native/node/view_model.cpp b/frameworks/core/interfaces/native/node/view_model.cpp index 0d0f046796fa3b2fba9455b05d7287315fac89df..e4475683148d67176e5cb86d97690e3280af5b6e 100644 --- a/frameworks/core/interfaces/native/node/view_model.cpp +++ b/frameworks/core/interfaces/native/node/view_model.cpp @@ -769,7 +769,9 @@ void RemoveChild(void* parentNode, void* childNode) CHECK_NULL_VOID(childNode); auto* parent = reinterpret_cast(parentNode); auto* child = reinterpret_cast(childNode); - child->MarkRemoving(); + if (!parent->IsFree()) { + child->MarkRemoving(); + } parent->RemoveChild(AceType::Claim(child), true); } diff --git a/frameworks/core/pipeline/base/element_register.cpp b/frameworks/core/pipeline/base/element_register.cpp index 58dec4cf48daad23e03cc99c13a65d0572216fa7..a64facc158736d9ee862a02744addb32635ef2ab 100644 --- a/frameworks/core/pipeline/base/element_register.cpp +++ b/frameworks/core/pipeline/base/element_register.cpp @@ -21,6 +21,8 @@ namespace OHOS::Ace { thread_local ElementRegister* ElementRegister::instance_ = nullptr; std::atomic ElementRegister::nextUniqueElementId_ = 0; std::mutex ElementRegister::mutex_; +std::shared_mutex ElementRegister::ThreadSafeNodeMapMutex_; +std::unordered_map> ElementRegister::ThreadSafeNodeMap_; ElementRegister* ElementRegister::GetInstance() { @@ -141,6 +143,9 @@ bool ElementRegister::AddUINode(const RefPtr& node) if (!node || (node->GetId() == ElementRegister::UndefinedElementId)) { return false; } + if (node->IsFree()) { + return AddThreadSafeNode(node); + } return AddReferenced(node->GetId(), node); } @@ -279,4 +284,34 @@ void ElementRegister::RemoveFrameNodeByInspectorId(const std::string& key, int32 inspectorIdMap_.erase(it); } } + +bool ElementRegister::AddThreadSafeNode(const RefPtr& node) +{ + std::unique_lock lock(ElementRegister::ThreadSafeNodeMapMutex_); + auto result = ElementRegister::ThreadSafeNodeMap_.emplace(node->GetId(), node); + if (!result.second) { + LOGE("Duplicate elmtId %{public}d error.", node->GetId()); + } + return result.second; +} + +RefPtr ElementRegister::GetThreadSafeNodeById(ElementIdType elementId) +{ + if (elementId == ElementRegister::UndefinedElementId) { + return nullptr; + } + std::shared_lock lock(ElementRegister::ThreadSafeNodeMapMutex_); + auto iter = ElementRegister::ThreadSafeNodeMap_.find(elementId); + return iter == ElementRegister::ThreadSafeNodeMap_.end() ? nullptr : + AceType::DynamicCast(iter->second).Upgrade(); +} + +bool ElementRegister::RemoveThreadSafeNode(ElementIdType elementId) +{ + if (elementId == ElementRegister::UndefinedElementId) { + return false; + } + std::unique_lock lock(ElementRegister::ThreadSafeNodeMapMutex_); + return ElementRegister::ThreadSafeNodeMap_.erase(elementId); +} } // namespace OHOS::Ace diff --git a/frameworks/core/pipeline/base/element_register.h b/frameworks/core/pipeline/base/element_register.h index 047b955734c58dbc8f79fcb320a9e6fc0bf2885d..d422560f40d53cdae24319880e5cad9947ef253f 100644 --- a/frameworks/core/pipeline/base/element_register.h +++ b/frameworks/core/pipeline/base/element_register.h @@ -17,6 +17,7 @@ #define FOUNDATION_ACE_FRAMEWORKS_CORE_COMPONENTS_BASE_ELEMENT_REGISTER_H #include +#include #include #include #include @@ -137,6 +138,10 @@ public: void RemoveFrameNodeByInspectorId(const std::string& key, int32_t nodeId); + bool AddThreadSafeNode(const RefPtr& node); + RefPtr GetThreadSafeNodeById(ElementIdType elementId); + bool RemoveThreadSafeNode(ElementIdType elementId); + private: // private constructor ElementRegister() = default; @@ -156,6 +161,9 @@ private: // Map for created elements std::unordered_map> itemMap_; + static std::shared_mutex ThreadSafeNodeMapMutex_; + static std::unordered_map> ThreadSafeNodeMap_; + // Map for inspectorId std::unordered_map>> inspectorIdMap_; diff --git a/interfaces/native/node/node_model.cpp b/interfaces/native/node/node_model.cpp index 4814eaa7c2b2777570902253e145d667e45a62c7..2eb585956edd39663bce872cd8862eab49a58d9e 100644 --- a/interfaces/native/node/node_model.cpp +++ b/interfaces/native/node/node_model.cpp @@ -133,7 +133,7 @@ bool IsValidArkUINode(ArkUI_NodeHandle nodePtr) if (!nodePtr) { return false; } - if (nodePtr->freeNode) { + if (nodePtr->threadSafeNode) { std::lock_guard lock(g_nodeSetMutex_); return g_nodeSetSafely.count(nodePtr) > 0; } else { @@ -143,7 +143,7 @@ bool IsValidArkUINode(ArkUI_NodeHandle nodePtr) void AddNodeSafely(ArkUI_NodeHandle nodePtr) { - if (nodePtr->freeNode) { + if (nodePtr->threadSafeNode) { std::lock_guard lock(g_nodeSetMutex_); g_nodeSetSafely.emplace(nodePtr); } else { @@ -153,7 +153,7 @@ void AddNodeSafely(ArkUI_NodeHandle nodePtr) void RemoveNodeSafely(ArkUI_NodeHandle nodePtr) { - if (nodePtr->freeNode) { + if (nodePtr->threadSafeNode) { std::lock_guard lock(g_nodeSetMutex_); g_nodeSetSafely.erase(nodePtr); } else { @@ -161,7 +161,7 @@ void RemoveNodeSafely(ArkUI_NodeHandle nodePtr) } } -ArkUI_NodeHandle CreateNodeInner(ArkUI_NodeType type, bool isFreeNode) +ArkUI_NodeHandle CreateNodeInner(ArkUI_NodeType type, bool isThreadSafeNode) { static const ArkUINodeType nodes[] = { ARKUI_CUSTOM, ARKUI_TEXT, ARKUI_SPAN, ARKUI_IMAGE_SPAN, ARKUI_IMAGE, ARKUI_TOGGLE, ARKUI_LOADING_PROGRESS, ARKUI_TEXT_INPUT, ARKUI_TEXTAREA, ARKUI_BUTTON, ARKUI_PROGRESS, @@ -185,7 +185,7 @@ ArkUI_NodeHandle CreateNodeInner(ArkUI_NodeType type, bool isFreeNode) return nullptr; } impl->getBasicAPI()->markDirty(uiNode, ARKUI_DIRTY_FLAG_ATTRIBUTE_DIFF); - ArkUI_Node* arkUINode = new ArkUI_Node({ type, uiNode, true, isFreeNode }); + ArkUI_Node* arkUINode = new ArkUI_Node({ type, uiNode, true, isThreadSafeNode }); impl->getExtendedAPI()->setAttachNodePtr(uiNode, reinterpret_cast(arkUINode)); AddNodeSafely(arkUINode); return arkUINode; diff --git a/interfaces/native/node/node_model.h b/interfaces/native/node/node_model.h index b913ef84ac5bbbdb92242b4d360db0daddaa3386..bb6445b8c783aa202486d2bcb0cfbf4498279b52 100644 --- a/interfaces/native/node/node_model.h +++ b/interfaces/native/node/node_model.h @@ -35,7 +35,7 @@ struct ArkUI_Node { int32_t type; ArkUINodeHandle uiNodeHandle = nullptr; bool cNode = false; - bool freeNode = false; + bool threadSafeNode = false; bool buildNode = false; void* extraData = nullptr; void* extraCustomData = nullptr; @@ -125,7 +125,7 @@ inline bool UsePXUnit(ArkUI_NodeHandle nodePtr) bool InitialFullImpl(); ArkUIFullNodeAPI* GetFullImpl(); -ArkUI_NodeHandle CreateNodeInner(ArkUI_NodeType type, bool isFreeNode); +ArkUI_NodeHandle CreateNodeInner(ArkUI_NodeType type, bool isThreadSafeNode); ArkUI_NodeHandle CreateNode(ArkUI_NodeType type); void DisposeNode(ArkUI_NodeHandle nativePtr); bool IsValidArkUINode(ArkUI_NodeHandle nodePtr); diff --git a/interfaces/native/node/node_model_safely.cpp b/interfaces/native/node/node_model_safely.cpp index d426f951e5a78a2df24492a997d013ea7fb23111..771d4b757507c5059c7fb4c7f25ee66180f3c822 100644 --- a/interfaces/native/node/node_model_safely.cpp +++ b/interfaces/native/node/node_model_safely.cpp @@ -58,22 +58,22 @@ int32_t OH_ArkUI_PostUITaskAndWait(ArkUI_ContextHandle context, void* taskData, #endif namespace OHOS::Ace::NodeModel { -class FreeNodeScope { +class ThreadSafeNodeScope { public: - explicit FreeNodeScope() + explicit ThreadSafeNodeScope() { - GetFullImpl()->getMultiThreadManagerAPI()->setIsFreeNodeScope(true); + GetFullImpl()->getMultiThreadManagerAPI()->setIsThreadSafeNodeScope(true); } - ~FreeNodeScope() + ~ThreadSafeNodeScope() { - GetFullImpl()->getMultiThreadManagerAPI()->setIsFreeNodeScope(false); + GetFullImpl()->getMultiThreadManagerAPI()->setIsThreadSafeNodeScope(false); } }; ArkUI_NodeHandle CreateNodeSafely(ArkUI_NodeType type) { - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return CreateNodeInner(type, true); } @@ -84,7 +84,7 @@ void DisposeNodeSafely(ArkUI_NodeHandle nativePtr) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nativePtr->uiNodeHandle)) { return; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; DisposeNode(nativePtr); } @@ -97,7 +97,7 @@ int32_t AddChildSafely(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childNode) !impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(childNode->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return AddChild(parentNode, childNode); } @@ -110,7 +110,7 @@ int32_t RemoveChildSafely(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childNod !impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(childNode->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return RemoveChild(parentNode, childNode); } @@ -123,7 +123,7 @@ int32_t InsertChildAfterSafely(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle chi !impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(childNode->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return InsertChildAfter(parentNode, childNode, siblingNode); } @@ -136,7 +136,7 @@ int32_t InsertChildBeforeSafely(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle ch !impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(childNode->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return InsertChildBefore(parentNode, childNode, siblingNode); } @@ -149,7 +149,7 @@ int32_t InsertChildAtSafely(ArkUI_NodeHandle parentNode, ArkUI_NodeHandle childN !impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(childNode->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return InsertChildAt(parentNode, childNode, position); } @@ -160,7 +160,7 @@ int32_t SetAttributeSafely(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attrib if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return SetAttribute(node, attribute, value); } @@ -171,7 +171,7 @@ int32_t ResetAttributeSafely(ArkUI_NodeHandle node, ArkUI_NodeAttributeType attr if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return ResetAttribute(node, attribute); } @@ -182,7 +182,7 @@ const ArkUI_AttributeItem* GetAttributeSafely(ArkUI_NodeHandle node, ArkUI_NodeA if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return nullptr; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetAttribute(node, attribute); } @@ -194,7 +194,7 @@ int32_t RegisterNodeEventSafely(ArkUI_NodeHandle nodePtr, if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nodePtr->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return RegisterNodeEvent(nodePtr, eventType, targetId, userData); } @@ -205,7 +205,7 @@ void UnregisterNodeEventSafely(ArkUI_NodeHandle nodePtr, ArkUI_NodeEventType eve if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nodePtr->uiNodeHandle)) { return; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; UnregisterNodeEvent(nodePtr, eventType); } @@ -252,7 +252,7 @@ int32_t SetLengthMetricUnitSafely(ArkUI_NodeHandle nodePtr, ArkUI_LengthMetricUn if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nodePtr->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return SetLengthMetricUnit(nodePtr, unit); } @@ -271,7 +271,7 @@ int32_t AddNodeEventReceiverSafely(ArkUI_NodeHandle nodePtr, void (*eventReceive if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nodePtr->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return AddNodeEventReceiver(nodePtr, eventReceiver); } @@ -282,7 +282,7 @@ int32_t RemoveNodeEventReceiverSafely(ArkUI_NodeHandle nodePtr, void (*eventRece if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nodePtr->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return RemoveNodeEventReceiver(nodePtr, eventReceiver); } @@ -294,7 +294,7 @@ int32_t RegisterNodeCustomEventSafely(ArkUI_NodeHandle node, if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return RegisterNodeCustomEvent(node, eventType, targetId, userData); } @@ -305,7 +305,7 @@ void UnregisterNodeCustomEventSafely(ArkUI_NodeHandle node, ArkUI_NodeCustomEven if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; UnregisterNodeCustomEvent(node, eventType); } @@ -332,7 +332,7 @@ int32_t AddNodeCustomEventReceiverSafely(ArkUI_NodeHandle nodePtr, void (*eventR if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nodePtr->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return AddNodeCustomEventReceiver(nodePtr, eventReceiver); } @@ -344,7 +344,7 @@ int32_t RemoveNodeCustomEventReceiverSafely(ArkUI_NodeHandle nodePtr, if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(nodePtr->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return RemoveNodeCustomEventReceiver(nodePtr, eventReceiver); } @@ -411,7 +411,7 @@ uint32_t GetTotalChildCountSafely(ArkUI_NodeHandle node) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return 0; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetTotalChildCount(node); } @@ -422,7 +422,7 @@ ArkUI_NodeHandle GetChildAtSafely(ArkUI_NodeHandle node, int32_t position) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return nullptr; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetChildAt(node, position); } @@ -433,7 +433,7 @@ ArkUI_NodeHandle GetFirstChildSafely(ArkUI_NodeHandle node) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return nullptr; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetFirstChild(node); } @@ -444,7 +444,7 @@ ArkUI_NodeHandle GetLastChildSafely(ArkUI_NodeHandle node) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return nullptr; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetLastChild(node); } @@ -455,7 +455,7 @@ ArkUI_NodeHandle GetPreviousSiblingSafely(ArkUI_NodeHandle node) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return nullptr; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetPreviousSibling(node); } @@ -466,7 +466,7 @@ ArkUI_NodeHandle GetNextSiblingSafely(ArkUI_NodeHandle node) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return nullptr; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetNextSibling(node); } @@ -477,7 +477,7 @@ ArkUI_NodeHandle GetParentSafely(ArkUI_NodeHandle node) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(node->uiNodeHandle)) { return nullptr; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return GetParent(node); } @@ -488,7 +488,7 @@ int32_t RemoveAllChildrenSafely(ArkUI_NodeHandle parentNode) if (!impl->getMultiThreadManagerAPI()->checkNodeOnValidThread(parentNode->uiNodeHandle)) { return ERROR_CODE_NATIVE_IMPL_NODE_ON_INVALID_THREAD; } - FreeNodeScope freeNodeScope; + ThreadSafeNodeScope threadSafeNodeScope; return RemoveAllChildren(parentNode); } } // namespace OHOS::Ace::NodeModel \ No newline at end of file diff --git a/interfaces/native/node/style_modifier.cpp b/interfaces/native/node/style_modifier.cpp index 225bd2a1f01812b05dbf0719f1ebd8dadafaba28..18c4a87400c479a7cb6b735517c6710e6ab0c1ab 100644 --- a/interfaces/native/node/style_modifier.cpp +++ b/interfaces/native/node/style_modifier.cpp @@ -189,9 +189,9 @@ constexpr int32_t REQUIRED_FIVE_PARAM = 5; constexpr int32_t REQUIRED_SEVEN_PARAM = 7; constexpr int32_t REQUIRED_TWENTY_PARAM = 20; constexpr int32_t MAX_ATTRIBUTE_ITEM_LEN = 20; -std::string g_stringValue; -ArkUI_NumberValue g_numberValues[MAX_ATTRIBUTE_ITEM_LEN] = { 0 }; -ArkUI_AttributeItem g_attributeItem = { g_numberValues, MAX_ATTRIBUTE_ITEM_LEN, nullptr, nullptr }; +thread_local std::string g_stringValue; +thread_local ArkUI_NumberValue g_numberValues[MAX_ATTRIBUTE_ITEM_LEN] = { 0 }; +thread_local ArkUI_AttributeItem g_attributeItem = { g_numberValues, MAX_ATTRIBUTE_ITEM_LEN, nullptr, nullptr }; constexpr uint32_t DEFAULT_COLOR = 0xFF000000; // Black constexpr uint32_t DEFAULT_FIll_COLOR = 0x00000000; diff --git a/test/mock/base/mock_system_properties.cpp b/test/mock/base/mock_system_properties.cpp index 0f0532a4ab46772c50b22ac341360ecbf07d4080..0efbcbf02020e76f7be4252e943515242e445df3 100644 --- a/test/mock/base/mock_system_properties.cpp +++ b/test/mock/base/mock_system_properties.cpp @@ -86,6 +86,7 @@ int32_t SystemProperties::imageFileCacheConvertAstcThreshold_ = 3; bool SystemProperties::taskPriorityAdjustmentEnable_ = false; int32_t SystemProperties::dragDropFrameworkStatus_ = 0; bool SystemProperties::pageTransitionFrzEnabled_ = false; +bool SystemProperties::debugThreadSafeNodeEnable_ = false; bool g_irregularGrid = true; bool g_segmentedWaterflow = true; diff --git a/test/mock/core/pipeline/mock_element_register.cpp b/test/mock/core/pipeline/mock_element_register.cpp index 6505acc89a5684d4fb51ebd360c7fe5d09fee795..d7d389aeb0ccb051d511508ebfb2627ce377c27e 100644 --- a/test/mock/core/pipeline/mock_element_register.cpp +++ b/test/mock/core/pipeline/mock_element_register.cpp @@ -24,6 +24,8 @@ namespace OHOS::Ace { thread_local ElementRegister* ElementRegister::instance_ = nullptr; std::atomic ElementRegister::nextUniqueElementId_ = 0; std::mutex ElementRegister::mutex_; +std::shared_mutex ElementRegister::ThreadSafeNodeMapMutex_; +std::unordered_map> ElementRegister::ThreadSafeNodeMap_; ElementRegister* ElementRegister::GetInstance() { @@ -123,6 +125,9 @@ bool ElementRegister::AddUINode(const RefPtr& node) if (!node || (node->GetId() == ElementRegister::UndefinedElementId)) { return false; } + if (node->IsFree()) { + return AddThreadSafeNode(node); + } return AddReferenced(node->GetId(), node); } @@ -254,4 +259,34 @@ void ElementRegister::RemoveFrameNodeByInspectorId(const std::string& key, int32 inspectorIdMap_.erase(it); } } + +bool ElementRegister::AddThreadSafeNode(const RefPtr& node) +{ + std::unique_lock lock(ElementRegister::ThreadSafeNodeMapMutex_); + auto result = ElementRegister::ThreadSafeNodeMap_.emplace(node->GetId(), node); + if (!result.second) { + LOGE("Duplicate elmtId %{public}d error.", node->GetId()); + } + return result.second; +} + +RefPtr ElementRegister::GetThreadSafeNodeById(ElementIdType elementId) +{ + if (elementId == ElementRegister::UndefinedElementId) { + return nullptr; + } + std::shared_lock lock(ElementRegister::ThreadSafeNodeMapMutex_); + auto iter = ElementRegister::ThreadSafeNodeMap_.find(elementId); + return iter == ElementRegister::ThreadSafeNodeMap_.end() ? nullptr : + AceType::DynamicCast(iter->second).Upgrade(); +} + +bool ElementRegister::RemoveThreadSafeNode(ElementIdType elementId) +{ + if (elementId == ElementRegister::UndefinedElementId) { + return false; + } + std::unique_lock lock(ElementRegister::ThreadSafeNodeMapMutex_); + return ElementRegister::ThreadSafeNodeMap_.erase(elementId); +} } // namespace OHOS::Ace diff --git a/test/unittest/core/base/BUILD.gn b/test/unittest/core/base/BUILD.gn index cd9d58edf64ffc660ea473bf7013bf56ceaf1e21..a82ce858e81bb7db81a7ad8bb49a3b3d26040efd 100644 --- a/test/unittest/core/base/BUILD.gn +++ b/test/unittest/core/base/BUILD.gn @@ -121,6 +121,12 @@ ace_unittest("extension_handler_test_ng") { sources = [ "extension_handler_test_ng.cpp" ] } +ace_unittest("thread_safe_node_test_ng") { + type = "new" + module_output = "basic" + sources = [ "thread_safe_node_test_ng.cpp" ] +} + group("core_base_unittest") { testonly = true deps = [ @@ -133,6 +139,7 @@ group("core_base_unittest") { ":observer_test_ng", ":short_cuts_little_test_ng", ":short_cuts_test_ng", + ":thread_safe_node_test_ng", ":ui_node_test_ng", ":view_abstract_model_test_ng", ":view_abstract_test_ng", diff --git a/test/unittest/core/base/thread_safe_node_test_ng.cpp b/test/unittest/core/base/thread_safe_node_test_ng.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f2d96f99e6edf805cdb3fe14e2b4ac364255bb2a --- /dev/null +++ b/test/unittest/core/base/thread_safe_node_test_ng.cpp @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2025 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "gtest/gtest.h" + +#define protected public +#define private public + +#include "test/mock/core/pipeline/mock_pipeline_context.h" + +#include "core/common/multi_thread_build_manager.h" +#include "core/components_ng/base/frame_node.h" +#include "core/components_ng/base/ui_node.h" +#include "core/components_ng/pattern/pattern.h" +#include "frameworks/core/pipeline/base/element_register.h" + +using namespace testing; +using namespace testing::ext; + +namespace OHOS::Ace::NG { +class ThreadSafeNodeTestNg : public testing::Test { +public: + static void SetUpTestSuite(); + static void TearDownTestSuite(); +}; + +void ThreadSafeNodeTestNg::SetUpTestSuite() +{ + MockPipelineContext::SetUp(); +} + +void ThreadSafeNodeTestNg::TearDownTestSuite() +{ + MockPipelineContext::TearDown(); +} + +/** + * @tc.name: ThreadSafeNodeTestNg001 + * @tc.desc: Test AddThreadSafeNode Repeated + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg001, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = AceType::MakeRefPtr("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + + /** + * @tc.steps: step2. thread safe uinode add to ElementRegister + * @tc.expected: add success + */ + EXPECT_EQ(ElementRegister::GetInstance()->AddUINode(frameNode), true); + + /** + * @tc.steps: step3. thread safe uinode add to ElementRegister again + * @tc.expected: add failed + */ + EXPECT_EQ(ElementRegister::GetInstance()->AddUINode(frameNode), false); +} + +/** + * @tc.name: ThreadSafeNodeTestNg002 + * @tc.desc: Test GetThreadSafeNodeById + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg002, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + + /** + * @tc.steps: step2. get the thread safe node which id is 1 from ElementRegister + * @tc.expected: get success + */ + EXPECT_EQ(ElementRegister::GetInstance()->GetThreadSafeNodeById(1), true); + + /** + * @tc.steps: step3. get the thread safe node which id is ElementRegister::UndefinedElementId from ElementRegister + * @tc.expected: get failed + */ + EXPECT_EQ(ElementRegister::GetInstance()->GetThreadSafeNodeById(ElementRegister::UndefinedElementId), false); +} + +/** + * @tc.name: ThreadSafeNodeTestNg003 + * @tc.desc: Test RemoveThreadSafeNode + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg003, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + + /** + * @tc.steps: step2. remove the thread safe node which id is 1 from ElementRegister + * @tc.expected: remove success + */ + EXPECT_EQ(ElementRegister::GetInstance()->RemoveThreadSafeNode(1), true); + + /** + * @tc.steps: step3. remove the thread safe node which + * id is ElementRegister::UndefinedElementId from ElementRegister + * @tc.expected: remove failed + */ + EXPECT_EQ(ElementRegister::GetInstance()->RemoveThreadSafeNode(ElementRegister::UndefinedElementId), false); +} + +/** + * @tc.name: ThreadSafeNodeTestNg004 + * @tc.desc: Test thread safe node RebuildRenderContextTree. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg004, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + + /** + * @tc.steps: step2. thread safe uinode RebuildRenderContextTree + * @tc.expected: rebuild success + */ + int32_t taskSize = frameNode->afterAttachMainTreeTasks_.size(); + frameNode->RebuildRenderContextTree(); + EXPECT_EQ(frameNode->afterAttachMainTreeTasks_.size(), taskSize + 1); +} + +/** + * @tc.name: ThreadSafeNodeTestNg005 + * @tc.desc: Test thread safe node MarkNeedRender. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg005, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + auto context = MockPipelineContext::GetCurrent(); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + frameNode->context_ = AceType::RawPtr(context); + frameNode->isRenderDirtyMarked_ = false; + frameNode->isLayoutDirtyMarked_ = false; + + /** + * @tc.steps: step2. thread safe uinode MarkNeedRender + * @tc.expected: mark success + */ + int32_t taskSize = frameNode->afterAttachMainTreeTasks_.size(); + frameNode->MarkNeedRender(true); + EXPECT_EQ(frameNode->afterAttachMainTreeTasks_.size(), taskSize + 1); + + /** + * @tc.steps: step3. create not thread safe uinode + */ + auto frameNode2 = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + frameNode2->context_ = AceType::RawPtr(context); + frameNode2->isRenderDirtyMarked_ = false; + frameNode2->isLayoutDirtyMarked_ = false; + + /** + * @tc.steps: step4. not thread safe uinode MarkNeedRender + * @tc.expected: mark success + */ + taskSize = frameNode2->afterAttachMainTreeTasks_.size(); + frameNode2->MarkNeedRender(true); + EXPECT_EQ(frameNode2 ->afterAttachMainTreeTasks_.size(), taskSize); +} + +/** + * @tc.name: ThreadSafeNodeTestNg006 + * @tc.desc: Test thread safe uinode create. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg006, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + * @tc.expected: create success + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + EXPECT_EQ(frameNode->isThreadSafeNode_, true); + EXPECT_EQ(frameNode->isFree_, true); +} + +/** + * @tc.name: ThreadSafeNodeTestNg007 + * @tc.desc: Test thread safe uinode release + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg007, TestSize.Level1) +{ + bool isUIThread = MultiThreadBuildManager::isUIThread_; + { + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + /** + * @tc.steps: step2. release thread safe uinode not on ui thread + * @tc.expected: release success + */ + MultiThreadBuildManager::isUIThread_ = false; + EXPECT_EQ(frameNode->isThreadSafeNode_, true); + EXPECT_EQ(frameNode->isFree_, true); + } + { + /** + * @tc.steps: step3. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + /** + * @tc.steps: step2. release thread safe uinode on ui thread + * @tc.expected: release success + */ + MultiThreadBuildManager::isUIThread_ = true; + EXPECT_EQ(frameNode->isThreadSafeNode_, true); + EXPECT_EQ(frameNode->isFree_, true); + } + MultiThreadBuildManager::isUIThread_ = isUIThread; +} + +/** + * @tc.name: ThreadSafeNodeTestNg0088 + * @tc.desc: Test uinode release + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg008, TestSize.Level1) +{ + bool isUIThread = MultiThreadBuildManager::isUIThread_; + { + /** + * @tc.steps: step1. create not thread safe uinode + */ + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + /** + * @tc.steps: step2. release not thread safe uinode not on ui thread + * @tc.expected: release success + */ + MultiThreadBuildManager::isUIThread_ = false; + EXPECT_EQ(frameNode->isThreadSafeNode_, false); + EXPECT_EQ(frameNode->isFree_, false); + } + { + /** + * @tc.steps: step3. create not thread safe uinode + */ + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + /** + * @tc.steps: step4. release not thread safe uinode on ui thread + * @tc.expected: release success + */ + MultiThreadBuildManager::isUIThread_ = true; + EXPECT_EQ(frameNode->isThreadSafeNode_, false); + EXPECT_EQ(frameNode->isFree_, false); + } + MultiThreadBuildManager::isUIThread_ = isUIThread; +} + +/** + * @tc.name: ThreadSafeNodeTestNg009 + * @tc.desc: Test thread safe uinode AttachToMainTree. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg009, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + + /** + * @tc.steps: step2. thread safe uinode AttachToMainTree and DetachFromMainTree + * @tc.expected: attach and detach success + */ + PipelineContext* pipeline = frameNode->GetContextWithCheck(); + frameNode->AttachToMainTree(false, pipeline); + EXPECT_EQ(frameNode->isFree_, false); + frameNode->DetachFromMainTree(false, false); + EXPECT_EQ(frameNode->isFree_, true); +} + +/** + * @tc.name: ThreadSafeNodeTestNg010 + * @tc.desc: Test thread safe uinode DetachFromMainTree. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg010, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + + /** + * @tc.steps: step2. thread safe uinode AttachToMainTree and DetachFromMainTree + * @tc.expected: attach and detach success + */ + PipelineContext* pipeline = frameNode->GetContextWithCheck(); + frameNode->AttachToMainTree(false, pipeline); + EXPECT_EQ(frameNode->isFree_, false); + frameNode->DetachFromMainTree(false, true); + EXPECT_EQ(frameNode->isFree_, true); +} + +/** + * @tc.name: ThreadSafeNodeTestNg011 + * @tc.desc: Test thread safe uinode tree DetachFromMainTree. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg011, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode tree + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + auto child = + FrameNode::CreateFrameNode("main", 2, AceType::MakeRefPtr(), true); + frameNode->AddChild(child); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + + /** + * @tc.steps: step2. thread safe uinode tree AttachToMainTree and DetachFromMainTree + * @tc.expected: attach and detach success + */ + PipelineContext* pipeline = frameNode->GetContextWithCheck(); + frameNode->AttachToMainTree(false, pipeline); + EXPECT_EQ(frameNode->isFree_, false); + frameNode->DetachFromMainTree(false, true); + EXPECT_EQ(frameNode->isFree_, true); +} + +/** + * @tc.name: ThreadSafeNodeTestNg012 + * @tc.desc: Test not thread safe ui node tree DetachFromMainTree. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg012, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + /** + * @tc.steps: step2. create not thread safe uinode tree + */ + auto child = + FrameNode::CreateFrameNode("main", 2, AceType::MakeRefPtr(), true); + frameNode->AddChild(child); + /** + * @tc.steps: step3. not thread safe uinode tree AttachToMainTree and DetachFromMainTree + * @tc.expected: attach and detach success + */ + PipelineContext* pipeline = frameNode->GetContextWithCheck(); + frameNode->AttachToMainTree(false, pipeline); + EXPECT_EQ(frameNode->isFree_, false); + frameNode->DetachFromMainTree(false, true); + EXPECT_EQ(frameNode->isFree_, true); +} + +/** + * @tc.name: ThreadSafeNodeTestNg013 + * @tc.desc: Test thread safe node MarkModifyDone. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg013, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + /** + * @tc.steps: step2. thread safe uinode MarkModifyDone + * @tc.expected: MarkModifyDone success + */ + int32_t taskSize = frameNode->afterAttachMainTreeTasks_.size(); + frameNode->MarkModifyDone(); + EXPECT_EQ(frameNode->afterAttachMainTreeTasks_.size(), taskSize + 1); +} + +/** + * @tc.name: ThreadSafeNodeTestNg014 + * @tc.desc: Test thread safe node MarkDirtyNode. + * @tc.type: FUNC + */ +HWTEST_F(ThreadSafeNodeTestNg, ThreadSafeNodeTestNg014, TestSize.Level1) +{ + /** + * @tc.steps: step1. create thread safe uinode + */ + MultiThreadBuildManager::SetIsThreadSafeNodeScope(true); + auto frameNode = + FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); + MultiThreadBuildManager::SetIsThreadSafeNodeScope(false); + /** + * @tc.steps: step2. thread safe uinode MarkDirtyNode + * @tc.expected: MarkDirtyNode success + */ + int32_t taskSize = frameNode->afterAttachMainTreeTasks_.size(); + frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE); + EXPECT_EQ(frameNode->afterAttachMainTreeTasks_.size(), taskSize + 1); +} +} // namespace OHOS::Ace::NG \ No newline at end of file diff --git a/test/unittest/core/base/ui_node_test_ng.cpp b/test/unittest/core/base/ui_node_test_ng.cpp index f7af1687cf844a9af0c5c447587782e84a1927ca..9e8dccdee57e70d25edfb528de668615f65a48d0 100644 --- a/test/unittest/core/base/ui_node_test_ng.cpp +++ b/test/unittest/core/base/ui_node_test_ng.cpp @@ -2590,191 +2590,4 @@ HWTEST_F(UINodeTestNg, AddFunc_API02, TestSize.Level1) EXPECT_EQ(testNode->children_.size(), 2); testNode->Clean(false); } - -/** - * @tc.name: FreeUINodeTestNg001 - * @tc.desc: Test free ui node create. - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg001, TestSize.Level1) -{ - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - EXPECT_EQ(frameNode->isFreeNode_, true); - EXPECT_EQ(frameNode->isFreeState_, true); -} - -/** - * @tc.name: FreeUINodeTestNg002 - * @tc.desc: Test free ui node release - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg002, TestSize.Level1) -{ - bool isUIThread = MultiThreadBuildManager::isUIThread_; - { - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - - MultiThreadBuildManager::isUIThread_ = false; - EXPECT_EQ(frameNode->isFreeNode_, true); - EXPECT_EQ(frameNode->isFreeState_, true); - } - { - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - - MultiThreadBuildManager::isUIThread_ = true; - EXPECT_EQ(frameNode->isFreeNode_, true); - EXPECT_EQ(frameNode->isFreeState_, true); - } - MultiThreadBuildManager::isUIThread_ = isUIThread; -} - -/** - * @tc.name: FreeUINodeTestNg003 - * @tc.desc: Test ui node release - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg003, TestSize.Level1) -{ - bool isUIThread = MultiThreadBuildManager::isUIThread_; - { - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - - MultiThreadBuildManager::isUIThread_ = false; - EXPECT_EQ(frameNode->isFreeNode_, false); - EXPECT_EQ(frameNode->isFreeState_, false); - } - { - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - - MultiThreadBuildManager::isUIThread_ = true; - EXPECT_EQ(frameNode->isFreeNode_, false); - EXPECT_EQ(frameNode->isFreeState_, false); - } - MultiThreadBuildManager::isUIThread_ = isUIThread; -} - -/** - * @tc.name: FreeUINodeTestNg004 - * @tc.desc: Test free ui node AttachToMainTree. - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg004, TestSize.Level1) -{ - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - - PipelineContext* pipeline = frameNode->GetContextWithCheck(); - frameNode->AttachToMainTree(false, pipeline); - EXPECT_EQ(frameNode->isFreeState_, false); - frameNode->DetachFromMainTree(false, false); - EXPECT_EQ(frameNode->isFreeState_, true); -} - -/** - * @tc.name: FreeUINodeTestNg005 - * @tc.desc: Test free ui node DetachFromMainTree. - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg005, TestSize.Level1) -{ - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - - PipelineContext* pipeline = frameNode->GetContextWithCheck(); - frameNode->AttachToMainTree(false, pipeline); - EXPECT_EQ(frameNode->isFreeState_, false); - frameNode->DetachFromMainTree(false, true); - EXPECT_EQ(frameNode->isFreeState_, true); -} - -/** - * @tc.name: FreeUINodeTestNg006 - * @tc.desc: Test free ui node tree DetachFromMainTree. - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg006, TestSize.Level1) -{ - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - auto child = - FrameNode::CreateFrameNode("main", 2, AceType::MakeRefPtr(), true); - frameNode->AddChild(child); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - - PipelineContext* pipeline = frameNode->GetContextWithCheck(); - frameNode->AttachToMainTree(false, pipeline); - EXPECT_EQ(frameNode->isFreeState_, false); - frameNode->DetachFromMainTree(false, true); - EXPECT_EQ(frameNode->isFreeState_, true); -} - -/** - * @tc.name: FreeUINodeTestNg007 - * @tc.desc: Test free ui node tree DetachFromMainTree. - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg007, TestSize.Level1) -{ - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - auto child = - FrameNode::CreateFrameNode("main", 2, AceType::MakeRefPtr(), true); - frameNode->AddChild(child); - - PipelineContext* pipeline = frameNode->GetContextWithCheck(); - frameNode->AttachToMainTree(false, pipeline); - EXPECT_EQ(frameNode->isFreeState_, false); - frameNode->DetachFromMainTree(false, true); - EXPECT_EQ(frameNode->isFreeState_, true); -} - -/** - * @tc.name: FreeUINodeTestNg008 - * @tc.desc: Test free node MarkModifyDone. - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg008, TestSize.Level1) -{ - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - frameNode->MarkModifyDone(); - EXPECT_EQ(frameNode->isFreeNode_, true); - EXPECT_EQ(frameNode->isFreeState_, true); -} - -/** - * @tc.name: FreeUINodeTestNg009 - * @tc.desc: Test free node MarkDirtyNode. - * @tc.type: FUNC - */ -HWTEST_F(UINodeTestNg, FreeUINodeTestNg009, TestSize.Level1) -{ - MultiThreadBuildManager::SetIsFreeNodeScope(true); - auto frameNode = - FrameNode::CreateFrameNode("main", 1, AceType::MakeRefPtr(), true); - MultiThreadBuildManager::SetIsFreeNodeScope(false); - frameNode->MarkDirtyNode(PROPERTY_UPDATE_MEASURE); - EXPECT_EQ(frameNode->isFreeNode_, true); - EXPECT_EQ(frameNode->isFreeState_, true); -} } // namespace OHOS::Ace::NG diff --git a/test/unittest/interfaces/native_node_napi_test.cpp b/test/unittest/interfaces/native_node_napi_test.cpp index 1501d79885cf9e80576ce8c7a168f6fac8830afd..57b9473127a1188a1145f88dfceecb0b22175c87 100644 --- a/test/unittest/interfaces/native_node_napi_test.cpp +++ b/test/unittest/interfaces/native_node_napi_test.cpp @@ -351,7 +351,7 @@ HWTEST_F(NativeNodeNapiTest, OH_ArkUI_PostAsyncUITaskAPITest001, TestSize.Level1 { ArkUI_ContextHandle uiContext = new ArkUI_Context({.id=10000}); auto ret = OH_ArkUI_PostAsyncUITask(uiContext, nullptr, [](void* asyncUITaskData){}, [](void* asyncUITaskData){}); - EXPECT_EQ(ret, ARKUI_ERROR_CODE_NO_ERROR); + EXPECT_NE(ret, ARKUI_ERROR_CODE_NO_ERROR); } /** diff --git a/test/unittest/interfaces/native_node_test.cpp b/test/unittest/interfaces/native_node_test.cpp index 670df43bff782aa1a87be683f4577a78a9103b48..95adc7507b13292c89a55e49d786e08b1ca361df 100644 --- a/test/unittest/interfaces/native_node_test.cpp +++ b/test/unittest/interfaces/native_node_test.cpp @@ -6679,15 +6679,15 @@ HWTEST_F(NativeNodeTest, NativeNodeTest144, TestSize.Level1) auto nodeAPI = reinterpret_cast( OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); - auto notFreeNode = nodeAPI->createNode(ARKUI_NODE_STACK); - EXPECT_EQ(NodeModel::IsValidArkUINode(notFreeNode), true); - nodeAPI->disposeNode(notFreeNode); + auto notThreadSafeNode = nodeAPI->createNode(ARKUI_NODE_STACK); + EXPECT_EQ(NodeModel::IsValidArkUINode(notThreadSafeNode), true); + nodeAPI->disposeNode(notThreadSafeNode); auto nodeAPI2 = reinterpret_cast( OH_ArkUI_QueryModuleInterfaceByName(ARKUI_MULTI_THREAD_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); - auto freeNode = nodeAPI2->createNode(ARKUI_NODE_STACK); - EXPECT_EQ(NodeModel::IsValidArkUINode(freeNode), true); - nodeAPI2->disposeNode(freeNode); + auto threadSafeNode = nodeAPI2->createNode(ARKUI_NODE_STACK); + EXPECT_EQ(NodeModel::IsValidArkUINode(threadSafeNode), true); + nodeAPI2->disposeNode(threadSafeNode); } /** @@ -6703,18 +6703,142 @@ HWTEST_F(NativeNodeTest, NativeNodeTest145, TestSize.Level1) auto nodeAPI = reinterpret_cast( OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); - auto notFreeNode = nodeAPI->createNode(ARKUI_NODE_STACK); + auto notThreadSafeNode = nodeAPI->createNode(ARKUI_NODE_STACK); ArkUINodeEvent event1; - event1.extraParam = reinterpret_cast(notFreeNode); + event1.extraParam = reinterpret_cast(notThreadSafeNode); EXPECT_EQ(NodeModel::GetNativeNodeEventType(&event1), -1); - nodeAPI->disposeNode(notFreeNode); + nodeAPI->disposeNode(notThreadSafeNode); auto nodeAPI2 = reinterpret_cast( OH_ArkUI_QueryModuleInterfaceByName(ARKUI_MULTI_THREAD_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); - auto freeNode = nodeAPI2->createNode(ARKUI_NODE_STACK); + auto threadSafeNode = nodeAPI2->createNode(ARKUI_NODE_STACK); ArkUINodeEvent event2; - event2.extraParam = reinterpret_cast(freeNode); + event2.extraParam = reinterpret_cast(threadSafeNode); EXPECT_EQ(NodeModel::GetNativeNodeEventType(&event2), -1); - nodeAPI2->disposeNode(freeNode); + nodeAPI2->disposeNode(threadSafeNode); +} + +/** + * @tc.name: NativeThreadSafeNodeTest001 + * @tc.desc: Test clearChildren + * @tc.type: FUNC + */ +HWTEST_F(NativeNodeTest, NativeThreadSafeNodeTest001, TestSize.Level1) +{ + /** + * @tc.steps: step1. create not thread safe native node + */ + auto nodeAPI = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));\ + ASSERT_NE(nodeAPI, nullptr); + auto notThreadSafeNode = nodeAPI->createNode(ARKUI_NODE_STACK); + auto notThreadSafeChildNode = nodeAPI->createNode(ARKUI_NODE_STACK); + ASSERT_NE(notThreadSafeNode, nullptr); + ASSERT_NE(notThreadSafeChildNode, nullptr); + /** + * @tc.steps: step2. add not thread safe child + */ + nodeAPI->addChild(notThreadSafeNode, notThreadSafeChildNode); + EXPECT_EQ(nodeAPI->getTotalChildCount(notThreadSafeNode), 1); + /** + * @tc.steps: step3. not thread safe native node remove all children + */ + nodeAPI->removeAllChildren(notThreadSafeNode); + ASSERT_NE(notThreadSafeChildNode->uiNodeHandle, nullptr); + auto* childNode = reinterpret_cast(notThreadSafeChildNode->uiNodeHandle); + ASSERT_NE(childNode, nullptr); + EXPECT_EQ(childNode->isRemoving_, true); + EXPECT_EQ(nodeAPI->getTotalChildCount(notThreadSafeNode), 0); + nodeAPI->disposeNode(notThreadSafeNode); + nodeAPI->disposeNode(notThreadSafeChildNode); + + /** + * @tc.steps: step4. create thread safe native node + */ + auto nodeAPI2 = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_MULTI_THREAD_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + ASSERT_NE(nodeAPI2, nullptr); + auto threadSafeNode = nodeAPI2->createNode(ARKUI_NODE_STACK); + auto threadSafeChildNode = nodeAPI2->createNode(ARKUI_NODE_STACK); + ASSERT_NE(threadSafeNode, nullptr); + ASSERT_NE(threadSafeChildNode, nullptr); + /** + * @tc.steps: step5. add thread safe child + */ + nodeAPI2->addChild(threadSafeNode, threadSafeChildNode); + EXPECT_EQ(nodeAPI2->getTotalChildCount(threadSafeNode), 1); + /** + * @tc.steps: step6. thread safe native node remove all children + */ + nodeAPI2->removeAllChildren(threadSafeNode); + ASSERT_NE(threadSafeChildNode->uiNodeHandle, nullptr); + auto* freeChildUINode = reinterpret_cast(threadSafeChildNode->uiNodeHandle); + ASSERT_NE(freeChildUINode, nullptr); + EXPECT_EQ(freeChildUINode->isRemoving_, false); + EXPECT_EQ(nodeAPI2->getTotalChildCount(threadSafeNode), 0); + nodeAPI2->disposeNode(threadSafeNode); + nodeAPI2->disposeNode(threadSafeChildNode); +} + +/** + * @tc.name: NativeThreadSafeNodeTest002 + * @tc.desc: Test removeChild + * @tc.type: FUNC + */ +HWTEST_F(NativeNodeTest, NativeThreadSafeNodeTest002, TestSize.Level1) +{ + /** + * @tc.steps: step1. create not thread safe native node + */ + auto nodeAPI = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_NATIVE_NODE, "ArkUI_NativeNodeAPI_1"));\ + ASSERT_NE(nodeAPI, nullptr); + auto notThreadSafeNode = nodeAPI->createNode(ARKUI_NODE_STACK); + auto notThreadSafeChildNode = nodeAPI->createNode(ARKUI_NODE_STACK); + ASSERT_NE(notThreadSafeNode, nullptr); + ASSERT_NE(notThreadSafeChildNode, nullptr); + /** + * @tc.steps: step2. add not thread safe child + */ + nodeAPI->addChild(notThreadSafeNode, notThreadSafeChildNode); + EXPECT_EQ(nodeAPI->getTotalChildCount(notThreadSafeNode), 1); + /** + * @tc.steps: step3. remove not thread safe child + */ + nodeAPI->removeChild(notThreadSafeNode, notThreadSafeChildNode); + ASSERT_NE(notThreadSafeChildNode->uiNodeHandle, nullptr); + auto* childNode = reinterpret_cast(notThreadSafeChildNode->uiNodeHandle); + ASSERT_NE(childNode, nullptr); + EXPECT_EQ(childNode->isRemoving_, true); + EXPECT_EQ(nodeAPI->getTotalChildCount(notThreadSafeNode), 0); + nodeAPI->disposeNode(notThreadSafeNode); + nodeAPI->disposeNode(notThreadSafeChildNode); + + /** + * @tc.steps: step4. create thread safe native node + */ + auto nodeAPI2 = reinterpret_cast( + OH_ArkUI_QueryModuleInterfaceByName(ARKUI_MULTI_THREAD_NATIVE_NODE, "ArkUI_NativeNodeAPI_1")); + ASSERT_NE(nodeAPI2, nullptr); + auto threadSafeNode = nodeAPI2->createNode(ARKUI_NODE_STACK); + auto threadSafeChildNode = nodeAPI2->createNode(ARKUI_NODE_STACK); + ASSERT_NE(threadSafeNode, nullptr); + ASSERT_NE(threadSafeChildNode, nullptr); + /** + * @tc.steps: step5. add thread safe child + */ + nodeAPI->addChild(threadSafeNode, threadSafeChildNode); + EXPECT_EQ(nodeAPI2->getTotalChildCount(threadSafeNode), 1); + /** + * @tc.steps: step6. remove thread safe child + */ + nodeAPI2->removeChild(threadSafeNode, threadSafeChildNode); + ASSERT_NE(threadSafeChildNode->uiNodeHandle, nullptr); + auto* freeChildUINode = reinterpret_cast(threadSafeChildNode->uiNodeHandle); + ASSERT_NE(freeChildUINode, nullptr); + EXPECT_EQ(freeChildUINode->isRemoving_, false); + EXPECT_EQ(nodeAPI2->getTotalChildCount(threadSafeNode), 0); + nodeAPI2->disposeNode(threadSafeNode); + nodeAPI2->disposeNode(threadSafeChildNode); } } // namespace OHOS::Ace \ No newline at end of file