1 /*
2 * Copyright (c) 2021-2022 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 "ui/rs_base_node.h"
17
18 #include <algorithm>
19 #include <sstream>
20
21 #include "sandbox_utils.h"
22
23 #include "command/rs_base_node_command.h"
24 #include "pipeline/rs_node_map.h"
25 #include "platform/common/rs_log.h"
26 #include "transaction/rs_transaction_proxy.h"
27 #include "ui/rs_canvas_node.h"
28 #include "ui/rs_display_node.h"
29 #include "ui/rs_proxy_node.h"
30 #include "ui/rs_root_node.h"
31 #include "ui/rs_surface_node.h"
32
33 namespace OHOS {
34 namespace Rosen {
35 namespace {
36 static bool gIsUniRenderEnabled = false;
37 }
38
GenerateId()39 NodeId RSBaseNode::GenerateId()
40 {
41 static pid_t pid_ = GetRealPid();
42 static std::atomic<uint32_t> currentId_ = 0;
43
44 auto currentId = currentId_.fetch_add(1, std::memory_order_relaxed);
45 if (currentId == UINT32_MAX) {
46 // [PLANNING]:process the overflow situations
47 ROSEN_LOGE("Node Id overflow");
48 }
49
50 // concat two 32-bit numbers to one 64-bit number
51 return ((NodeId)pid_ << 32) | currentId;
52 }
53
InitUniRenderEnabled()54 void RSBaseNode::InitUniRenderEnabled()
55 {
56 static bool inited = false;
57 if (!inited) {
58 inited = true;
59 gIsUniRenderEnabled = RSSystemProperties::GetUniRenderEnabled();
60 ROSEN_LOGD("RSBaseNode::InitUniRenderEnabled:%d", gIsUniRenderEnabled);
61 }
62 }
63
RSBaseNode(bool isRenderServiceNode)64 RSBaseNode::RSBaseNode(bool isRenderServiceNode) : RSBaseNode(isRenderServiceNode, GenerateId()) {}
65
RSBaseNode(bool isRenderServiceNode,NodeId id)66 RSBaseNode::RSBaseNode(bool isRenderServiceNode, NodeId id) : isRenderServiceNode_(isRenderServiceNode), id_(id)
67 {
68 InitUniRenderEnabled();
69 }
70
~RSBaseNode()71 RSBaseNode::~RSBaseNode()
72 {
73 // break current (ui) parent-child relationship.
74 // render nodes will check if its child is expired and remove it, no need to manually remove it here.
75 if (auto parentPtr = RSNodeMap::Instance().GetNode(parent_)) {
76 parentPtr->RemoveChildById(id_);
77 }
78 // unregister node from node map
79 RSNodeMap::MutableInstance().UnregisterNode(id_);
80
81 // tell RT/RS to destroy related render node
82 auto transactionProxy = RSTransactionProxy::GetInstance();
83 if (transactionProxy == nullptr || skipDestroyCommandInDestructor_) {
84 return;
85 }
86 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeDestroy>(id_);
87 transactionProxy->AddCommand(command, IsRenderServiceNode());
88 if (NeedSendExtraCommand()) {
89 std::unique_ptr<RSCommand> extraCommand = std::make_unique<RSBaseNodeDestroy>(id_);
90 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode());
91 }
92 }
93
IsUniRenderEnabled() const94 bool RSBaseNode::IsUniRenderEnabled() const
95 {
96 return gIsUniRenderEnabled;
97 }
98
IsRenderServiceNode() const99 bool RSBaseNode::IsRenderServiceNode() const
100 {
101 return gIsUniRenderEnabled || isRenderServiceNode_;
102 }
103
NeedSendExtraCommand() const104 bool RSBaseNode::NeedSendExtraCommand() const
105 {
106 return gIsUniRenderEnabled && !isRenderServiceNode_;
107 }
108
AddChild(SharedPtr child,int index)109 void RSBaseNode::AddChild(SharedPtr child, int index)
110 {
111 if (child == nullptr) {
112 ROSEN_LOGE("RSBaseNode::AddChild, child is nullptr");
113 return;
114 }
115 if (child->parent_ == id_) {
116 ROSEN_LOGI("RSBaseNode::AddChild, child already exist");
117 return;
118 }
119 NodeId childId = child->GetId();
120 if (child->parent_ != 0) {
121 child->RemoveFromTree();
122 }
123
124 if (index < 0 || index >= static_cast<int>(children_.size())) {
125 children_.push_back(childId);
126 } else {
127 children_.insert(children_.begin() + index, childId);
128 }
129 child->SetParent(id_);
130 child->OnAddChildren();
131 auto transactionProxy = RSTransactionProxy::GetInstance();
132 if (transactionProxy == nullptr) {
133 return;
134 }
135 // construct command using child's GetHierarchyCommandNodeId(), not GetId()
136 childId = child->GetHierarchyCommandNodeId();
137 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeAddChild>(id_, childId, index);
138 bool disallowSendToRemote = gIsUniRenderEnabled && !RSSystemProperties::IsUniRenderMode() && // dynamic-Non Uni
139 !isRenderServiceNode_ && !IsInstanceOf(RSUINodeType::SURFACE_NODE) && // canvas/root node
140 child->IsInstanceOf(RSUINodeType::SURFACE_NODE);
141 if (disallowSendToRemote) {
142 transactionProxy->AddCommand(command, false, GetFollowType(), id_);
143 return;
144 }
145 transactionProxy->AddCommand(command, IsRenderServiceNode(), GetFollowType(), id_);
146 if (NeedSendExtraCommand()) {
147 std::unique_ptr<RSCommand> extraCommand = std::make_unique<RSBaseNodeAddChild>(id_, childId, index);
148 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode(), GetFollowType(), id_);
149 }
150 }
151
MoveChild(SharedPtr child,int index)152 void RSBaseNode::MoveChild(SharedPtr child, int index)
153 {
154 if (child == nullptr || child->parent_ != id_) {
155 ROSEN_LOGD("RSBaseNode::MoveChild, not valid child");
156 return;
157 }
158 NodeId childId = child->GetId();
159 auto itr = std::find(children_.begin(), children_.end(), childId);
160 if (itr == children_.end()) {
161 ROSEN_LOGD("RSBaseNode::MoveChild, not child");
162 return;
163 }
164 children_.erase(itr);
165 if (index < 0 || index >= static_cast<int>(children_.size())) {
166 children_.push_back(childId);
167 } else {
168 children_.insert(children_.begin() + index, childId);
169 }
170
171 auto transactionProxy = RSTransactionProxy::GetInstance();
172 if (transactionProxy == nullptr) {
173 return;
174 }
175 // construct command using child's GetHierarchyCommandNodeId(), not GetId()
176 childId = child->GetHierarchyCommandNodeId();
177 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeMoveChild>(id_, childId, index);
178 bool disallowSendToRemote = gIsUniRenderEnabled && !RSSystemProperties::IsUniRenderMode() && // dynamic-Non Uni
179 !isRenderServiceNode_ &&
180 !IsInstanceOf(RSUINodeType::SURFACE_NODE) && // canvas/root node
181 child->IsInstanceOf(RSUINodeType::SURFACE_NODE);
182 if (disallowSendToRemote) {
183 transactionProxy->AddCommand(command, false, GetFollowType(), id_);
184 return;
185 }
186 transactionProxy->AddCommand(command, IsRenderServiceNode(), GetFollowType(), id_);
187 if (NeedSendExtraCommand()) {
188 std::unique_ptr<RSCommand> extraCommand = std::make_unique<RSBaseNodeMoveChild>(id_, childId, index);
189 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode(), GetFollowType(), id_);
190 }
191 }
192
RemoveChild(SharedPtr child)193 void RSBaseNode::RemoveChild(SharedPtr child)
194 {
195 if (child == nullptr || child->parent_ != id_) {
196 ROSEN_LOGI("RSBaseNode::RemoveChild, child is nullptr");
197 return;
198 }
199 NodeId childId = child->GetId();
200 RemoveChildById(childId);
201 child->OnRemoveChildren();
202 child->SetParent(0);
203
204 auto transactionProxy = RSTransactionProxy::GetInstance();
205 if (transactionProxy == nullptr) {
206 return;
207 }
208 // construct command using child's GetHierarchyCommandNodeId(), not GetId()
209 childId = child->GetHierarchyCommandNodeId();
210 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeRemoveChild>(id_, childId);
211 transactionProxy->AddCommand(command, IsRenderServiceNode(), GetFollowType(), id_);
212 if (NeedSendExtraCommand()) {
213 std::unique_ptr<RSCommand> extraCommand = std::make_unique<RSBaseNodeRemoveChild>(id_, childId);
214 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode(), GetFollowType(), id_);
215 }
216 }
217
AddCrossParentChild(SharedPtr child,int index)218 void RSBaseNode::AddCrossParentChild(SharedPtr child, int index)
219 {
220 // AddCrossParentChild only used as: the child is under multiple parents(e.g. a window cross multi-screens),
221 // so this child will not remove from the old parent.
222 if (child == nullptr) {
223 ROSEN_LOGE("RSBaseNode::AddCrossScreenChild, child is nullptr");
224 return;
225 }
226 if (!this->IsInstanceOf<RSDisplayNode>()) {
227 ROSEN_LOGE("RSBaseNode::AddCrossScreenChild, only displayNode support AddCrossScreenChild");
228 return;
229 }
230 NodeId childId = child->GetId();
231
232 if (index < 0 || index >= static_cast<int>(children_.size())) {
233 children_.push_back(childId);
234 } else {
235 children_.insert(children_.begin() + index, childId);
236 }
237 child->SetParent(id_);
238 child->OnAddChildren();
239 auto transactionProxy = RSTransactionProxy::GetInstance();
240 if (transactionProxy == nullptr) {
241 return;
242 }
243 // construct command using child's GetHierarchyCommandNodeId(), not GetId()
244 childId = child->GetHierarchyCommandNodeId();
245 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeAddCrossParentChild>(id_, childId, index);
246 bool disallowSendToRemote = gIsUniRenderEnabled && !RSSystemProperties::IsUniRenderMode() && // dynamic-Non Uni
247 !isRenderServiceNode_ &&
248 !IsInstanceOf(RSUINodeType::SURFACE_NODE) && // canvas/root node
249 child->IsInstanceOf(RSUINodeType::SURFACE_NODE);
250 if (disallowSendToRemote) {
251 transactionProxy->AddCommand(command, false, GetFollowType(), id_);
252 return;
253 }
254 transactionProxy->AddCommand(command, IsRenderServiceNode(), GetFollowType(), id_);
255 if (NeedSendExtraCommand()) {
256 std::unique_ptr<RSCommand> extraCommand = std::make_unique<RSBaseNodeAddCrossParentChild>(id_, childId, index);
257 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode(), GetFollowType(), id_);
258 }
259 }
260
RemoveCrossParentChild(SharedPtr child,NodeId newParentId)261 void RSBaseNode::RemoveCrossParentChild(SharedPtr child, NodeId newParentId)
262 {
263 // RemoveCrossParentChild only used as: the child is under multiple parents(e.g. a window cross multi-screens),
264 // set the newParentId to rebuild the parent-child relationship.
265 if (child == nullptr) {
266 ROSEN_LOGI("RSBaseNode::RemoveCrossScreenChild, child is nullptr");
267 return;
268 }
269 if (!this->IsInstanceOf<RSDisplayNode>()) {
270 ROSEN_LOGE("RSBaseNode::RemoveCrossScreenChild, only displayNode support RemoveCrossScreenChild");
271 return;
272 }
273 NodeId childId = child->GetId();
274 RemoveChildById(childId);
275 child->OnRemoveChildren();
276 child->SetParent(newParentId);
277
278 auto transactionProxy = RSTransactionProxy::GetInstance();
279 if (transactionProxy == nullptr) {
280 return;
281 }
282 // construct command using child's GetHierarchyCommandNodeId(), not GetId()
283 childId = child->GetHierarchyCommandNodeId();
284 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeRemoveCrossParentChild>(id_, childId, newParentId);
285 transactionProxy->AddCommand(command, IsRenderServiceNode(), GetFollowType(), id_);
286 if (NeedSendExtraCommand()) {
287 std::unique_ptr<RSCommand> extraCommand =
288 std::make_unique<RSBaseNodeRemoveCrossParentChild>(id_, childId, newParentId);
289 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode(), GetFollowType(), id_);
290 }
291 }
292
RemoveChildById(NodeId childId)293 void RSBaseNode::RemoveChildById(NodeId childId)
294 {
295 auto itr = std::find(children_.begin(), children_.end(), childId);
296 if (itr != children_.end()) {
297 children_.erase(itr);
298 }
299 }
300
RemoveFromTree()301 void RSBaseNode::RemoveFromTree()
302 {
303 if (auto parentPtr = RSNodeMap::Instance().GetNode(parent_)) {
304 parentPtr->RemoveChildById(GetId());
305 OnRemoveChildren();
306 SetParent(0);
307 }
308 // always send Remove-From-Tree command
309 auto transactionProxy = RSTransactionProxy::GetInstance();
310 if (transactionProxy == nullptr) {
311 return;
312 }
313 // construct command using own GetHierarchyCommandNodeId(), not GetId()
314 auto nodeId = GetHierarchyCommandNodeId();
315 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeRemoveFromTree>(nodeId);
316 transactionProxy->AddCommand(command, IsRenderServiceNode(), GetFollowType(), nodeId);
317 if (NeedSendExtraCommand()) {
318 std::unique_ptr<RSCommand> extraCommand = std::make_unique<RSBaseNodeRemoveFromTree>(nodeId);
319 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode(), GetFollowType(), nodeId);
320 }
321 }
322
ClearChildren()323 void RSBaseNode::ClearChildren()
324 {
325 for (auto child : children_) {
326 if (auto childPtr = RSNodeMap::Instance().GetNode(child)) {
327 childPtr->SetParent(0);
328 }
329 }
330 children_.clear();
331
332 auto transactionProxy = RSTransactionProxy::GetInstance();
333 if (transactionProxy == nullptr) {
334 return;
335 }
336 // construct command using own GetHierarchyCommandNodeId(), not GetId()
337 auto nodeId = GetHierarchyCommandNodeId();
338 std::unique_ptr<RSCommand> command = std::make_unique<RSBaseNodeClearChild>(nodeId);
339 transactionProxy->AddCommand(command, IsRenderServiceNode(), GetFollowType(), nodeId);
340 if (NeedSendExtraCommand()) {
341 std::unique_ptr<RSCommand> extraCommand = std::make_unique<RSBaseNodeClearChild>(nodeId);
342 transactionProxy->AddCommand(extraCommand, !IsRenderServiceNode(), GetFollowType(), nodeId);
343 }
344 }
345
SetParent(NodeId parentId)346 void RSBaseNode::SetParent(NodeId parentId)
347 {
348 parent_ = parentId;
349 }
350
GetParent()351 RSBaseNode::SharedPtr RSBaseNode::GetParent()
352 {
353 return RSNodeMap::Instance().GetNode(parent_);
354 }
355
DumpNode(int depth) const356 std::string RSBaseNode::DumpNode(int depth) const
357 {
358 std::stringstream ss;
359 auto it = RSUINodeTypeStrs.find(GetType());
360 if (it == RSUINodeTypeStrs.end()) {
361 return "";
362 }
363 ss << it->second << "[" << std::to_string(id_) << "] child[";
364 for (auto child : children_) {
365 ss << std::to_string(child) << " ";
366 }
367 ss << "]";
368 return ss.str();
369 }
370
IsInstanceOf(RSUINodeType type) const371 bool RSBaseNode::IsInstanceOf(RSUINodeType type) const
372 {
373 auto targetType = static_cast<uint32_t>(type);
374 auto instanceType = static_cast<uint32_t>(GetType());
375 // use bitmask to check whether the instance is a subclass of the target type
376 return (instanceType & targetType) == targetType;
377 }
378
379 template<typename T>
IsInstanceOf() const380 bool RSBaseNode::IsInstanceOf() const
381 {
382 return IsInstanceOf(T::Type);
383 }
384
385 // explicit instantiation with all render node types
386 template bool RSBaseNode::IsInstanceOf<RSBaseNode>() const;
387 template bool RSBaseNode::IsInstanceOf<RSDisplayNode>() const;
388 template bool RSBaseNode::IsInstanceOf<RSNode>() const;
389 template bool RSBaseNode::IsInstanceOf<RSSurfaceNode>() const;
390 template bool RSBaseNode::IsInstanceOf<RSProxyNode>() const;
391 template bool RSBaseNode::IsInstanceOf<RSCanvasNode>() const;
392 template bool RSBaseNode::IsInstanceOf<RSRootNode>() const;
393
394 } // namespace Rosen
395 } // namespace OHOS
396