• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 constexpr int32_t ENDORSE_LAYOUT_COUNT = 2;
29 } // namespace
30 uint64_t UITaskScheduler::frameId_ = 0;
31 
UITaskScheduler()32 UITaskScheduler::UITaskScheduler()
33 {
34     if (access(LIBFFRT_LIB64_PATH, F_OK) == -1) {
35         return;
36     }
37     is64BitSystem_ = true;
38 }
39 
~UITaskScheduler()40 UITaskScheduler::~UITaskScheduler()
41 {
42     persistAfterLayoutTasks_.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             child->GetRenderContext()->SetExtraOffset(offset);
77         }
78     }
79 }
80 
AddDirtyRenderNode(const RefPtr<FrameNode> & dirty)81 void UITaskScheduler::AddDirtyRenderNode(const RefPtr<FrameNode>& dirty)
82 {
83     CHECK_RUN_ON(UI);
84     CHECK_NULL_VOID(dirty);
85     auto result = dirtyRenderNodes_[dirty->GetPageId()].emplace(dirty);
86     if (!result.second) {
87         LOGW("Fail to emplace %{public}s render node", dirty->GetTag().c_str());
88     }
89 }
90 
ExpandSafeArea()91 void UITaskScheduler::ExpandSafeArea()
92 {
93     auto pipeline = PipelineContext::GetCurrentContext();
94     CHECK_NULL_VOID(pipeline);
95     auto safeAreaManager = pipeline->GetSafeAreaManager();
96     CHECK_NULL_VOID(safeAreaManager);
97     safeAreaManager->ExpandSafeArea();
98 }
99 
FlushSyncGeometryNodeTasks()100 void UITaskScheduler::FlushSyncGeometryNodeTasks()
101 {
102     ACE_LAYOUT_SCOPED_TRACE("FlushSyncGeometryNodeTasks");
103     ExpandSafeArea();
104     SetLayoutNodeRect();
105     auto tasks = std::move(syncGeometryNodeTasks_);
106     for (auto& task : tasks) {
107         if (task) {
108             task();
109         }
110     }
111 }
112 
FlushLayoutTask(bool forceUseMainThread)113 void UITaskScheduler::FlushLayoutTask(bool forceUseMainThread)
114 {
115     CHECK_RUN_ON(UI);
116     ACE_FUNCTION_TRACE_COMMERCIAL();
117     if (dirtyLayoutNodes_.empty()) {
118         return;
119     }
120     if (isLayouting_ && SystemProperties::GetLayoutDetectEnabled()) {
121         LOGF_ABORT("you are already in flushing layout!");
122     }
123 
124 #ifdef FFRT_EXISTS
125     // Pause GC during long frame
126     std::unique_ptr<ILongFrame> longFrame = std::make_unique<ILongFrame>();
127     if (is64BitSystem_) {
128         ACE_LAYOUT_SCOPED_TRACE("ReportStartEvent");
129         longFrame->ReportStartEvent();
130     }
131 #endif
132 
133     isLayouting_ = true;
134     auto dirtyLayoutNodes = std::move(dirtyLayoutNodes_);
135     PageDirtySet dirtyLayoutNodesSet(dirtyLayoutNodes.begin(), dirtyLayoutNodes.end());
136 
137     // Priority task creation
138     int64_t time = 0;
139     for (auto&& node : dirtyLayoutNodesSet) {
140         // need to check the node is destroying or not before CreateLayoutTask
141         if (!node || node->IsInDestroying()) {
142             continue;
143         }
144         time = GetSysTimestamp();
145         node->CreateLayoutTask(forceUseMainThread);
146         time = GetSysTimestamp() - time;
147         if (frameInfo_ != nullptr) {
148             frameInfo_->AddTaskInfo(node->GetTag(), node->GetId(), time, FrameInfo::TaskType::LAYOUT);
149         }
150     }
151     FlushSyncGeometryNodeTasks();
152 #ifdef FFRT_EXISTS
153     if (is64BitSystem_) {
154         ACE_LAYOUT_SCOPED_TRACE("ReportEndEvent");
155         longFrame->ReportEndEvent();
156     }
157 #endif
158 
159     isLayouting_ = false;
160 }
161 
FlushRenderTask(bool forceUseMainThread)162 void UITaskScheduler::FlushRenderTask(bool forceUseMainThread)
163 {
164     CHECK_RUN_ON(UI);
165     if (FrameReport::GetInstance().GetEnable()) {
166         FrameReport::GetInstance().BeginFlushRender();
167     }
168     auto dirtyRenderNodes = std::move(dirtyRenderNodes_);
169     // Priority task creation
170     int64_t time = 0;
171     for (auto&& pageNodes : dirtyRenderNodes) {
172         ACE_SCOPED_TRACE_COMMERCIAL("FlushRenderTask %zu", pageNodes.second.size());
173         for (auto&& node : pageNodes.second) {
174             if (!node) {
175                 continue;
176             }
177             if (node->IsInDestroying()) {
178                 // reset RenderDirtyMarked for recycle node
179                 node->ResetRenderDirtyMarked(false);
180                 continue;
181             }
182             time = GetSysTimestamp();
183             auto task = node->CreateRenderTask(forceUseMainThread);
184             if (task) {
185                 if (forceUseMainThread || (task->GetTaskThreadType() == MAIN_TASK)) {
186                     (*task)();
187                     time = GetSysTimestamp() - time;
188                     if (frameInfo_ != nullptr) {
189                         frameInfo_->AddTaskInfo(node->GetTag(), node->GetId(), time, FrameInfo::TaskType::RENDER);
190                     }
191                 }
192             }
193         }
194     }
195 }
196 
NeedAdditionalLayout()197 bool UITaskScheduler::NeedAdditionalLayout()
198 {
199     bool ret = false;
200     ElementRegister::GetInstance()->ReSyncGeometryTransition();
201 
202     RootDirtyMap dirtyLayoutNodesMap;
203     for (auto&& dirty : dirtyLayoutNodes_) {
204         dirtyLayoutNodesMap[dirty->GetPageId()].emplace(dirty);
205     }
206 
207     for (auto&& pageNodes : dirtyLayoutNodesMap) {
208         for (auto&& node : pageNodes.second) {
209             if (!node || node->IsInDestroying() || !node->GetLayoutProperty()) {
210                 continue;
211             }
212             const auto& geometryTransition = node->GetLayoutProperty()->GetGeometryTransition();
213             if (geometryTransition != nullptr) {
214                 ret |= geometryTransition->OnAdditionalLayout(node);
215             }
216         }
217     }
218     return ret;
219 }
220 
FlushTaskWithCheck(bool triggeredByImplicitAnimation)221 void UITaskScheduler::FlushTaskWithCheck(bool triggeredByImplicitAnimation)
222 {
223     layoutWithImplicitAnimation_.push(triggeredByImplicitAnimation);
224     if (IsLayouting()) {
225         multiLayoutCount_++;
226         return;
227     }
228     FlushTask();
229 }
230 
FlushTask()231 void UITaskScheduler::FlushTask()
232 {
233     CHECK_RUN_ON(UI);
234     ACE_SCOPED_TRACE("UITaskScheduler::FlushTask");
235     // update for first entry from flushVSync
236     // and reset to avoid infinite add
237     int32_t layoutedCount = 0;
238     multiLayoutCount_ = 1;
239     singleDirtyNodesToFlush_.clear();
240     do {
241         if (layoutedCount >= ENDORSE_LAYOUT_COUNT && RequestFrameOnLayoutCountExceeds()) {
242             break;
243         }
244         FlushLayoutTask();
245         if (NeedAdditionalLayout()) {
246             FlushLayoutTask();
247         }
248         if (!afterLayoutTasks_.empty()) {
249             FlushAfterLayoutTask();
250         }
251         layoutedCount++;
252         multiLayoutCount_--;
253         FlushSafeAreaPaddingProcess();
254         auto triggeredByImplicitAnimation =
255             layoutWithImplicitAnimation_.empty() ? false : layoutWithImplicitAnimation_.front();
256         if (!triggeredByImplicitAnimation && !afterLayoutCallbacksInImplicitAnimationTask_.empty()) {
257             FlushAfterLayoutCallbackInImplicitAnimationTask();
258         }
259         if (!layoutWithImplicitAnimation_.empty()) {
260             layoutWithImplicitAnimation_.pop();
261         }
262     } while (multiLayoutCount_ > 0);
263     // abandon unused params
264     layoutWithImplicitAnimation_ = std::queue<bool>();
265     FlushAllSingleNodeTasks();
266     multiLayoutCount_ = 0;
267     ElementRegister::GetInstance()->ClearPendingRemoveNodes();
268     FlushRenderTask();
269 }
270 
FlushAllSingleNodeTasks()271 void UITaskScheduler::FlushAllSingleNodeTasks()
272 {
273     // handle case of components executing FlushUITaskWithSingleDirtyNode during FlushLayoutTask
274     if (singleDirtyNodesToFlush_.empty()) {
275         return;
276     }
277     ACE_SCOPED_TRACE("Flush after-layout singleNode task, count %zu", singleDirtyNodesToFlush_.size());
278     auto pipeline = PipelineContext::GetCurrentContextPtrSafelyWithCheck();
279     CHECK_NULL_VOID(pipeline);
280     auto singleDirtyNodes = std::move(singleDirtyNodesToFlush_);
281     for (const auto& node : singleDirtyNodes) {
282         // skip if already flushed by any previous tasks
283         if (!node || (!node->IsLayoutDirtyMarked() && !node->CheckNeedForceMeasureAndLayout())) {
284             continue;
285         }
286         pipeline->FlushUITaskWithSingleDirtyNode(node);
287     }
288 }
289 
AddSingleNodeToFlush(const RefPtr<FrameNode> & dirtyNode)290 void UITaskScheduler::AddSingleNodeToFlush(const RefPtr<FrameNode>& dirtyNode)
291 {
292     singleDirtyNodesToFlush_.insert(dirtyNode);
293 }
294 
RequestFrameOnLayoutCountExceeds()295 bool UITaskScheduler::RequestFrameOnLayoutCountExceeds()
296 {
297     auto pipeline = PipelineContext::GetCurrentContextPtrSafelyWithCheck();
298     if (pipeline) {
299         pipeline->RequestFrame();
300     }
301     return true;
302 }
303 
AddSafeAreaPaddingProcessTask(FrameNode * node)304 void UITaskScheduler::AddSafeAreaPaddingProcessTask(FrameNode* node)
305 {
306     safeAreaPaddingProcessTasks_.insert(node);
307 }
308 
RemoveSafeAreaPaddingProcessTask(FrameNode * node)309 void UITaskScheduler::RemoveSafeAreaPaddingProcessTask(FrameNode* node)
310 {
311     safeAreaPaddingProcessTasks_.erase(node);
312 }
313 
FlushSafeAreaPaddingProcess()314 void UITaskScheduler::FlushSafeAreaPaddingProcess()
315 {
316     if (safeAreaPaddingProcessTasks_.empty()) {
317         return;
318     }
319     auto safeAreaPaddingProcessTasks = safeAreaPaddingProcessTasks_;
320     auto iter = safeAreaPaddingProcessTasks.begin();
321     while (iter != safeAreaPaddingProcessTasks.end()) {
322         auto node = *iter;
323         if (!node) {
324             iter = safeAreaPaddingProcessTasks.erase(iter);
325         } else {
326             node->ProcessSafeAreaPadding();
327             ++iter;
328         }
329     }
330     // clear caches after all process tasks
331     iter = safeAreaPaddingProcessTasks.begin();
332     while (iter != safeAreaPaddingProcessTasks.end()) {
333         auto node = *iter;
334         if (node) {
335             const auto& geometryNode = node->GetGeometryNode();
336             if (geometryNode) {
337                 geometryNode->ResetAccumulatedSafeAreaPadding();
338             }
339         }
340         ++iter;
341     }
342 
343     auto eraseIter = safeAreaPaddingProcessTasks_.begin();
344     while (eraseIter != safeAreaPaddingProcessTasks_.end()) {
345         auto node = *eraseIter;
346         if (!node) {
347             eraseIter = safeAreaPaddingProcessTasks_.erase(eraseIter);
348         } else {
349             ++eraseIter;
350         }
351     }
352 }
353 
AddPredictTask(PredictTask && task)354 void UITaskScheduler::AddPredictTask(PredictTask&& task)
355 {
356     predictTask_.push_back(std::move(task));
357 }
358 
FlushPredictTask(int64_t deadline,bool canUseLongPredictTask)359 void UITaskScheduler::FlushPredictTask(int64_t deadline, bool canUseLongPredictTask)
360 {
361     decltype(predictTask_) tasks(std::move(predictTask_));
362     for (const auto& task : tasks) {
363         if (task) {
364             task(deadline, canUseLongPredictTask);
365         }
366     }
367 }
368 
CleanUp()369 void UITaskScheduler::CleanUp()
370 {
371     dirtyLayoutNodes_.clear();
372     dirtyRenderNodes_.clear();
373 }
374 
isEmpty()375 bool UITaskScheduler::isEmpty()
376 {
377     return dirtyLayoutNodes_.empty() && dirtyRenderNodes_.empty();
378 }
379 
IsPredictTaskEmpty()380 bool UITaskScheduler::IsPredictTaskEmpty()
381 {
382     return predictTask_.empty();
383 }
384 
AddAfterLayoutTask(std::function<void ()> && task,bool isFlushInImplicitAnimationTask)385 void UITaskScheduler::AddAfterLayoutTask(std::function<void()>&& task, bool isFlushInImplicitAnimationTask)
386 {
387     if (isFlushInImplicitAnimationTask) {
388         afterLayoutCallbacksInImplicitAnimationTask_.emplace_back(std::move(task));
389     } else {
390         afterLayoutTasks_.emplace_back(std::move(task));
391     }
392 }
393 
AddPersistAfterLayoutTask(std::function<void ()> && task)394 void UITaskScheduler::AddPersistAfterLayoutTask(std::function<void()>&& task)
395 {
396     persistAfterLayoutTasks_.emplace_back(std::move(task));
397     LOGI("AddPersistAfterLayoutTask size: %{public}u", static_cast<uint32_t>(persistAfterLayoutTasks_.size()));
398 }
399 
FlushAfterLayoutTask()400 void UITaskScheduler::FlushAfterLayoutTask()
401 {
402     decltype(afterLayoutTasks_) tasks(std::move(afterLayoutTasks_));
403     for (const auto& task : tasks) {
404         if (task) {
405             task();
406         }
407     }
408     // flush correct rect again and flush dirty node again
409     FlushPersistAfterLayoutTask();
410 }
411 
FlushAfterLayoutCallbackInImplicitAnimationTask()412 void UITaskScheduler::FlushAfterLayoutCallbackInImplicitAnimationTask()
413 {
414     decltype(afterLayoutCallbacksInImplicitAnimationTask_) tasks(
415         std::move(afterLayoutCallbacksInImplicitAnimationTask_));
416     for (const auto& task : tasks) {
417         if (task) {
418             task();
419         }
420     }
421 }
422 
FlushPersistAfterLayoutTask()423 void UITaskScheduler::FlushPersistAfterLayoutTask()
424 {
425     // only execute after layout
426     if (persistAfterLayoutTasks_.empty()) {
427         return;
428     }
429     ACE_SCOPED_TRACE("UITaskScheduler::FlushPersistAfterLayoutTask");
430     for (const auto& task : persistAfterLayoutTasks_) {
431         if (task) {
432             task();
433         }
434     }
435 }
436 
AddAfterRenderTask(std::function<void ()> && task)437 void UITaskScheduler::AddAfterRenderTask(std::function<void()>&& task)
438 {
439     afterRenderTasks_.emplace_back(std::move(task));
440 }
441 
FlushAfterRenderTask()442 void UITaskScheduler::FlushAfterRenderTask()
443 {
444     ACE_SCOPED_TRACE("UITaskScheduler::FlushAfterRenderTask");
445     decltype(afterRenderTasks_) tasks(std::move(afterRenderTasks_));
446     for (const auto& task : tasks) {
447         if (task) {
448             task();
449         }
450     }
451 }
452 
453 } // namespace OHOS::Ace::NG
454