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