• 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 }
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