1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "core/common/multi_thread_build_manager.h"
17
18 #ifdef FFRT_SUPPORT
19 #include "ffrt_inner.h"
20 #endif
21 #include "base/log/log_wrapper.h"
22 #include "base/log/ace_trace.h"
23 #include "base/memory/referenced.h"
24 #include "base/utils/system_properties.h"
25 #include "core/common/container.h"
26 #include "core/pipeline_ng/pipeline_context.h"
27
28 namespace OHOS::Ace {
29 namespace {
30 #ifdef FFRT_SUPPORT
31 constexpr uint32_t MAX_THREAD_NUM = 3;
32 constexpr uint32_t ASYNC_UITASK_QOS = 5;
33 std::unique_ptr<ffrt::queue> asyncUITaskQueue = nullptr;
34 #endif
35 }
36 thread_local bool MultiThreadBuildManager::isThreadSafeNodeScope_ = false;
37 thread_local bool MultiThreadBuildManager::isUIThread_ = false;
38
GetInstance()39 MultiThreadBuildManager& MultiThreadBuildManager::GetInstance()
40 {
41 static MultiThreadBuildManager MultiThreadBuildManager;
42 return MultiThreadBuildManager;
43 }
44
MultiThreadBuildManager()45 MultiThreadBuildManager::MultiThreadBuildManager()
46 {
47 InitAsyncUITaskQueue();
48 }
49
InitOnUIThread()50 void MultiThreadBuildManager::InitOnUIThread()
51 {
52 isUIThread_ = true;
53 }
54
InitAsyncUITaskQueue()55 void MultiThreadBuildManager::InitAsyncUITaskQueue()
56 {
57 #ifdef FFRT_SUPPORT
58 asyncUITaskQueue = std::make_unique<ffrt::queue>(ffrt::queue_concurrent,
59 "ArkUIAsyncUITask", ffrt::queue_attr().max_concurrency(MAX_THREAD_NUM));
60 #endif
61 }
62
IsOnUIThread()63 bool MultiThreadBuildManager::IsOnUIThread()
64 {
65 return isUIThread_;
66 }
67
CheckOnUIThread()68 bool MultiThreadBuildManager::CheckOnUIThread()
69 {
70 if (!IsOnUIThread()) {
71 TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "CheckOnUIThread failed");
72 return false;
73 }
74 return true;
75 }
76
CheckNodeOnValidThread(NG::UINode * node)77 bool MultiThreadBuildManager::CheckNodeOnValidThread(NG::UINode* node)
78 {
79 if (!node) {
80 TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "CheckNodeOnValidThread failed. node is nullptr");
81 return false;
82 }
83 if (!node->IsFree() && !MultiThreadBuildManager::IsOnUIThread()) {
84 TAG_LOGE(AceLogTag::ACE_NATIVE_NODE, "CheckNodeOnValidThread failed. unfree node not run on main thread");
85 return false;
86 }
87 return true;
88 }
89
SetIsThreadSafeNodeScope(bool isThreadSafeNodeScope)90 void MultiThreadBuildManager::SetIsThreadSafeNodeScope(bool isThreadSafeNodeScope)
91 {
92 isThreadSafeNodeScope_ = isThreadSafeNodeScope;
93 }
94
IsThreadSafeNodeScope()95 bool MultiThreadBuildManager::IsThreadSafeNodeScope()
96 {
97 return isThreadSafeNodeScope_ || SystemProperties::GetDebugThreadSafeNodeEnabled();
98 }
99
PostAsyncUITask(int32_t contextId,std::function<void ()> && asyncUITask,std::function<void ()> && onFinishTask)100 bool MultiThreadBuildManager::PostAsyncUITask(int32_t contextId, std::function<void()>&& asyncUITask,
101 std::function<void()>&& onFinishTask)
102 {
103 ContainerScope scope(contextId);
104 auto container = Container::Current();
105 CHECK_NULL_RETURN(container, false);
106 auto taskExecutor = container->GetTaskExecutor();
107 CHECK_NULL_RETURN(taskExecutor, false);
108 #ifdef FFRT_SUPPORT
109 if (!asyncUITaskQueue) {
110 return false;
111 }
112 auto result = asyncUITaskQueue->submit_h([contextId,
113 asyncUITask = std::move(asyncUITask), onFinishTask = std::move(onFinishTask)]() {
114 ContainerScope scope(contextId);
115 asyncUITask();
116 auto container = Container::Current();
117 CHECK_NULL_VOID(container);
118 auto taskExecutor = container->GetTaskExecutor();
119 CHECK_NULL_VOID(taskExecutor);
120 taskExecutor->PostTask([contextId, onFinishTask = std::move(onFinishTask)]() {
121 ContainerScope scope(contextId);
122 onFinishTask();
123 }, TaskExecutor::TaskType::UI, "ArkUIAsyncUIOnFinishTask", PriorityType::IMMEDIATE);
124 }, ffrt::task_attr().qos(ASYNC_UITASK_QOS));
125 return result != nullptr;
126 #else
127 return taskExecutor->PostTask([contextId,
128 asyncUITask = std::move(asyncUITask), onFinishTask = std::move(onFinishTask)]() {
129 ContainerScope scope(contextId);
130 asyncUITask();
131 auto container = Container::Current();
132 CHECK_NULL_VOID(container);
133 auto taskExecutor = container->GetTaskExecutor();
134 CHECK_NULL_VOID(taskExecutor);
135 taskExecutor->PostTask([contextId, onFinishTask = std::move(onFinishTask)]() {
136 ContainerScope scope(contextId);
137 onFinishTask();
138 }, TaskExecutor::TaskType::UI, "ArkUIAsyncUIOnFinishTask", PriorityType::IMMEDIATE);
139 }, TaskExecutor::TaskType::BACKGROUND, "ArkUIAsyncUITask");
140 #endif
141 }
142
PostUITask(int32_t contextId,std::function<void ()> && uiTask)143 bool MultiThreadBuildManager::PostUITask(int32_t contextId, std::function<void()>&& uiTask)
144 {
145 ContainerScope scope(contextId);
146 auto container = Container::Current();
147 CHECK_NULL_RETURN(container, false);
148 auto taskExecutor = container->GetTaskExecutor();
149 CHECK_NULL_RETURN(taskExecutor, false);
150 return taskExecutor->PostTask([contextId, uiTask = std::move(uiTask)]() {
151 ContainerScope scope(contextId);
152 uiTask();
153 }, TaskExecutor::TaskType::UI, "ArkUISyncUITask", PriorityType::IMMEDIATE);
154 }
155
PostUITaskAndWait(int32_t contextId,std::function<void ()> && uiTask)156 bool MultiThreadBuildManager::PostUITaskAndWait(int32_t contextId, std::function<void()>&& uiTask)
157 {
158 ContainerScope scope(contextId);
159 auto container = Container::Current();
160 CHECK_NULL_RETURN(container, false);
161 auto taskExecutor = container->GetTaskExecutor();
162 CHECK_NULL_RETURN(taskExecutor, false);
163 return taskExecutor->PostSyncTask([contextId, uiTask = std::move(uiTask)]() {
164 ContainerScope scope(contextId);
165 uiTask();
166 }, TaskExecutor::TaskType::UI, "ArkUISyncTaskAndWait", PriorityType::IMMEDIATE);
167 }
168 } // namespace OHOS::Ace