1 /*
2 * Copyright (c) 2022-2023 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/pipeline_ng/ui_task_scheduler.h"
17
18 #include <unistd.h>
19
20 #ifdef FFRT_EXISTS
21 #include "base/longframe/long_frame_report.h"
22 #endif
23 #include "core/pipeline_ng/pipeline_context.h"
24
25 namespace OHOS::Ace::NG {
26 namespace {
27 constexpr char LIBFFRT_LIB64_PATH[] = "/system/lib64/ndk/libffrt.z.so";
28 }
29 uint64_t UITaskScheduler::frameId_ = 0;
30
UITaskScheduler()31 UITaskScheduler::UITaskScheduler()
32 {
33 if (access(LIBFFRT_LIB64_PATH, F_OK) == -1) {
34 return ;
35 }
36 is64BitSystem_ = true;
37 }
38
~UITaskScheduler()39 UITaskScheduler::~UITaskScheduler()
40 {
41 persistAfterLayoutTasks_.clear();
42 latestFrameLayoutFinishTasks_.clear();
43 }
44
AddDirtyLayoutNode(const RefPtr<FrameNode> & dirty)45 void UITaskScheduler::AddDirtyLayoutNode(const RefPtr<FrameNode>& dirty)
46 {
47 CHECK_RUN_ON(UI);
48 CHECK_NULL_VOID(dirty);
49 dirtyLayoutNodes_.emplace_back(dirty);
50 }
51
AddLayoutNode(const RefPtr<FrameNode> & layoutNode)52 void UITaskScheduler::AddLayoutNode(const RefPtr<FrameNode>& layoutNode)
53 {
54 CHECK_RUN_ON(UI);
55 CHECK_NULL_VOID(layoutNode);
56 layoutNodes_.emplace_back(layoutNode);
57 }
58
SetLayoutNodeRect()59 void UITaskScheduler::SetLayoutNodeRect()
60 {
61 if (layoutNodes_.empty()) {
62 return;
63 }
64 auto layoutNodes = std::move(layoutNodes_);
65 LayoutNodesSet layoutNodesSet(layoutNodes.begin(), layoutNodes.end());
66
67 for (auto& layoutNode : layoutNodesSet) {
68 if (layoutNode->GetIsFind()) {
69 layoutNode->SetIsFind(false);
70 continue;
71 }
72 std::list<RefPtr<FrameNode>> children;
73 OffsetF offset;
74 layoutNode->GetOneDepthVisibleFrameWithOffset(children, offset);
75 for (auto& child : children) {
76 auto paintRect = child->GetRenderContext()->GetPaintRectWithoutTransform();
77 paintRect.SetOffset(paintRect.GetOffset() + offset);
78 child->GetRenderContext()->UpdatePaintRect(paintRect);
79 }
80 }
81 }
82
83
AddDirtyRenderNode(const RefPtr<FrameNode> & dirty)84 void UITaskScheduler::AddDirtyRenderNode(const RefPtr<FrameNode>& dirty)
85 {
86 CHECK_RUN_ON(UI);
87 CHECK_NULL_VOID(dirty);
88 auto result = dirtyRenderNodes_[dirty->GetPageId()].emplace(dirty);
89 if (!result.second) {
90 LOGW("Fail to emplace %{public}s render node", dirty->GetTag().c_str());
91 }
92 }
93
ExpandSafeArea()94 void UITaskScheduler::ExpandSafeArea()
95 {
96 auto pipeline = PipelineContext::GetCurrentContext();
97 CHECK_NULL_VOID(pipeline);
98 auto safeAreaManager = pipeline->GetSafeAreaManager();
99 CHECK_NULL_VOID(safeAreaManager);
100 safeAreaManager->ExpandSafeArea();
101 }
102
FlushSyncGeometryNodeTasks()103 void UITaskScheduler::FlushSyncGeometryNodeTasks()
104 {
105 ACE_LAYOUT_SCOPED_TRACE("FlushSyncGeometryNodeTasks");
106 ExpandSafeArea();
107 SetLayoutNodeRect();
108 auto tasks = std::move(syncGeometryNodeTasks_);
109 for (auto& task : tasks) {
110 if (task) {
111 task();
112 }
113 }
114 }
115
FlushLayoutTask(bool forceUseMainThread)116 void UITaskScheduler::FlushLayoutTask(bool forceUseMainThread)
117 {
118 CHECK_RUN_ON(UI);
119 ACE_FUNCTION_TRACE();
120 if (dirtyLayoutNodes_.empty()) {
121 return;
122 }
123 #ifdef FFRT_EXISTS
124 // Pause GC during long frame
125 std::unique_ptr<ILongFrame> longFrame = std::make_unique<ILongFrame>();
126 if (is64BitSystem_) {
127 ACE_LAYOUT_SCOPED_TRACE("ReportStartEvent");
128 longFrame->ReportStartEvent();
129 }
130 #endif
131
132 isLayouting_ = true;
133 auto dirtyLayoutNodes = std::move(dirtyLayoutNodes_);
134 PageDirtySet dirtyLayoutNodesSet(dirtyLayoutNodes.begin(), dirtyLayoutNodes.end());
135
136 // Priority task creation
137 int64_t time = 0;
138 for (auto&& node : dirtyLayoutNodesSet) {
139 // need to check the node is destroying or not before CreateLayoutTask
140 if (!node || node->IsInDestroying()) {
141 continue;
142 }
143 time = GetSysTimestamp();
144 node->CreateLayoutTask(forceUseMainThread);
145 time = GetSysTimestamp() - time;
146 if (frameInfo_ != nullptr) {
147 frameInfo_->AddTaskInfo(node->GetTag(), node->GetId(), time, FrameInfo::TaskType::LAYOUT);
148 }
149 }
150 FlushSyncGeometryNodeTasks();
151 #ifdef FFRT_EXISTS
152 if (is64BitSystem_) {
153 ACE_LAYOUT_SCOPED_TRACE("ReportEndEvent");
154 longFrame->ReportEndEvent();
155 }
156 #endif
157
158 isLayouting_ = false;
159 }
160
FlushRenderTask(bool forceUseMainThread)161 void UITaskScheduler::FlushRenderTask(bool forceUseMainThread)
162 {
163 CHECK_RUN_ON(UI);
164 if (FrameReport::GetInstance().GetEnable()) {
165 FrameReport::GetInstance().BeginFlushRender();
166 }
167 auto dirtyRenderNodes = std::move(dirtyRenderNodes_);
168 // Priority task creation
169 int64_t time = 0;
170 for (auto&& pageNodes : dirtyRenderNodes) {
171 ACE_SCOPED_TRACE("FlushRenderTask %zu", pageNodes.second.size());
172 for (auto&& node : pageNodes.second) {
173 if (!node) {
174 continue;
175 }
176 if (node->IsInDestroying()) {
177 continue;
178 }
179 time = GetSysTimestamp();
180 auto task = node->CreateRenderTask(forceUseMainThread);
181 if (task) {
182 if (forceUseMainThread || (task->GetTaskThreadType() == MAIN_TASK)) {
183 (*task)();
184 time = GetSysTimestamp() - time;
185 if (frameInfo_ != nullptr) {
186 frameInfo_->AddTaskInfo(node->GetTag(), node->GetId(), time, FrameInfo::TaskType::RENDER);
187 }
188 }
189 }
190 }
191 }
192 }
193
NeedAdditionalLayout()194 bool UITaskScheduler::NeedAdditionalLayout()
195 {
196 bool ret = false;
197 ElementRegister::GetInstance()->ReSyncGeometryTransition();
198
199 RootDirtyMap dirtyLayoutNodesMap;
200 for (auto&& dirty : dirtyLayoutNodes_) {
201 dirtyLayoutNodesMap[dirty->GetPageId()].emplace(dirty);
202 }
203
204 for (auto&& pageNodes : dirtyLayoutNodesMap) {
205 for (auto&& node : pageNodes.second) {
206 if (!node || node->IsInDestroying() || !node->GetLayoutProperty()) {
207 continue;
208 }
209 const auto& geometryTransition = node->GetLayoutProperty()->GetGeometryTransition();
210 if (geometryTransition != nullptr) {
211 ret |= geometryTransition->OnAdditionalLayout(node);
212 }
213 }
214 }
215 return ret;
216 }
217
FlushTask(bool triggeredByImplicitAnimation)218 void UITaskScheduler::FlushTask(bool triggeredByImplicitAnimation)
219 {
220 CHECK_RUN_ON(UI);
221 ACE_SCOPED_TRACE("UITaskScheduler::FlushTask");
222 FlushLayoutTask();
223 if (NeedAdditionalLayout()) {
224 FlushLayoutTask();
225 }
226 if (!afterLayoutTasks_.empty()) {
227 FlushAfterLayoutTask();
228 }
229 if (!triggeredByImplicitAnimation && !afterLayoutCallbacksInImplicitAnimationTask_.empty()) {
230 FlushAfterLayoutCallbackInImplicitAnimationTask();
231 }
232 ElementRegister::GetInstance()->ClearPendingRemoveNodes();
233 FlushRenderTask();
234 }
235
AddPredictTask(PredictTask && task)236 void UITaskScheduler::AddPredictTask(PredictTask&& task)
237 {
238 predictTask_.push_back(std::move(task));
239 }
240
FlushPredictTask(int64_t deadline,bool canUseLongPredictTask)241 void UITaskScheduler::FlushPredictTask(int64_t deadline, bool canUseLongPredictTask)
242 {
243 decltype(predictTask_) tasks(std::move(predictTask_));
244 for (const auto& task : tasks) {
245 if (task) {
246 task(deadline, canUseLongPredictTask);
247 }
248 }
249 }
250
CleanUp()251 void UITaskScheduler::CleanUp()
252 {
253 dirtyLayoutNodes_.clear();
254 dirtyRenderNodes_.clear();
255 }
256
isEmpty()257 bool UITaskScheduler::isEmpty()
258 {
259 return dirtyLayoutNodes_.empty() && dirtyRenderNodes_.empty();
260 }
261
AddAfterLayoutTask(std::function<void ()> && task,bool isFlushInImplicitAnimationTask)262 void UITaskScheduler::AddAfterLayoutTask(std::function<void()>&& task, bool isFlushInImplicitAnimationTask)
263 {
264 if (isFlushInImplicitAnimationTask) {
265 afterLayoutCallbacksInImplicitAnimationTask_.emplace_back(std::move(task));
266 } else {
267 afterLayoutTasks_.emplace_back(std::move(task));
268 }
269 }
270
AddPersistAfterLayoutTask(std::function<void ()> && task)271 void UITaskScheduler::AddPersistAfterLayoutTask(std::function<void()>&& task)
272 {
273 persistAfterLayoutTasks_.emplace_back(std::move(task));
274 LOGI("AddPersistAfterLayoutTask size: %{public}u", static_cast<uint32_t>(persistAfterLayoutTasks_.size()));
275 }
276
AddLatestFrameLayoutFinishTask(std::function<void ()> && task)277 void UITaskScheduler::AddLatestFrameLayoutFinishTask(std::function<void()>&& task)
278 {
279 latestFrameLayoutFinishTasks_.emplace_back(std::move(task));
280 LOGI("AddLatestFrameLayoutFinishTask size: %{public}u",
281 static_cast<uint32_t>(latestFrameLayoutFinishTasks_.size()));
282 }
283
FlushAfterLayoutTask()284 void UITaskScheduler::FlushAfterLayoutTask()
285 {
286 decltype(afterLayoutTasks_) tasks(std::move(afterLayoutTasks_));
287 for (const auto& task : tasks) {
288 if (task) {
289 task();
290 }
291 }
292 // flush correct rect again and flush dirty node again
293 FlushPersistAfterLayoutTask();
294 }
295
FlushAfterLayoutCallbackInImplicitAnimationTask()296 void UITaskScheduler::FlushAfterLayoutCallbackInImplicitAnimationTask()
297 {
298 decltype(afterLayoutCallbacksInImplicitAnimationTask_) tasks(
299 std::move(afterLayoutCallbacksInImplicitAnimationTask_));
300 for (const auto& task : tasks) {
301 if (task) {
302 task();
303 }
304 }
305 }
306
FlushPersistAfterLayoutTask()307 void UITaskScheduler::FlushPersistAfterLayoutTask()
308 {
309 // only execute after layout
310 if (persistAfterLayoutTasks_.empty()) {
311 return;
312 }
313 ACE_SCOPED_TRACE("UITaskScheduler::FlushPersistAfterLayoutTask");
314 for (const auto& task : persistAfterLayoutTasks_) {
315 if (task) {
316 task();
317 }
318 }
319 }
320
FlushLatestFrameLayoutFinishTask()321 void UITaskScheduler::FlushLatestFrameLayoutFinishTask()
322 {
323 // only execute after latest layout finish
324 if (latestFrameLayoutFinishTasks_.empty()) {
325 return;
326 }
327 ACE_SCOPED_TRACE("UITaskScheduler::FlushLatestFrameLayoutFinishTask");
328 for (const auto& task : latestFrameLayoutFinishTasks_) {
329 if (task) {
330 task();
331 }
332 }
333 }
334
AddAfterRenderTask(std::function<void ()> && task)335 void UITaskScheduler::AddAfterRenderTask(std::function<void()>&& task)
336 {
337 afterRenderTasks_.emplace_back(std::move(task));
338 }
339
FlushAfterRenderTask()340 void UITaskScheduler::FlushAfterRenderTask()
341 {
342 ACE_SCOPED_TRACE("UITaskScheduler::FlushAfterRenderTask");
343 decltype(afterRenderTasks_) tasks(std::move(afterRenderTasks_));
344 for (const auto& task : tasks) {
345 if (task) {
346 task();
347 }
348 }
349 }
350
351 } // namespace OHOS::Ace::NG
352