已合并
crossNode节点收集适配 #31940
sunzy创建于 8月3日
crossNode节点收集适配 #31940
已合并
共 3 个文件变更+256-0
| @@ -1199,6 +1199,26 @@ void RSUniRenderVisitor::CollectHwcAndFilterNodesToParent(RSRenderNode& node, bo | |||
| 1199 | } | 1199 | } |
| 1200 | } | 1200 | } |
| 1201 | 1201 | ||
| 1202 | +void RSUniRenderVisitor::CollectHwcAndFilterNodesForCrossNode(RSSurfaceRenderNode& node, | ||
| 1203 | + bool isParentPrepareInReverseOrder) | ||
| 1204 | +{ | ||
| 1205 | + auto sourceRenderNode = node.GetSourceCrossNode().lock(); | ||
| 1206 | + auto sourceSurfaceNode = sourceRenderNode ? | ||
| 1207 | + sourceRenderNode->ReinterpretCastTo<RSSurfaceRenderNode>() : nullptr; | ||
| 1208 | + if (sourceSurfaceNode) { | ||
| 1209 | + // Clone: mirror the source's aggregated list into the current node. | ||
| 1210 | + auto& cloneNodeList = node.GetAllHwcNodeAndFilterNode(); | ||
| 1211 | + cloneNodeList = sourceSurfaceNode->GetAllHwcNodeAndFilterNode(); | ||
L | |||
| 1212 | + } else if (node.IsCloneCrossNode()) { | ||
| 1213 | + // Error case: no resolvable source, drop stale data. | ||
| 1214 | + node.ClearAllHwcNodeAndFilterNode(); | ||
| 1215 | + } | ||
| 1216 | + if (curScreenNode_ && curScreenNode_->GetId() != node.GetId()) { | ||
| 1217 | + CollectHwcAndFilterNodesToParent(node, isParentPrepareInReverseOrder, | ||
| 1218 | + RSUniHwcComputeUtil::IsBlendNeedFilter(node)); | ||
| 1219 | + } | ||
| 1220 | +} | ||
| 1221 | + | ||
| 1202 | void RSUniRenderVisitor::QuickPrepareDepthRenderNode(RSDepthRenderNode& node, bool isParentPrepareInReverseOrder) | 1222 | void RSUniRenderVisitor::QuickPrepareDepthRenderNode(RSDepthRenderNode& node, bool isParentPrepareInReverseOrder) |
| 1203 | { | 1223 | { |
| 1204 | RS_OPTIONAL_TRACE_BEGIN_LEVEL(TRACE_LEVEL_PRINT_NODEID, "QuickPrepareDepthRenderNode nodeId[%llu]", node.GetId()); | 1224 | RS_OPTIONAL_TRACE_BEGIN_LEVEL(TRACE_LEVEL_PRINT_NODEID, "QuickPrepareDepthRenderNode nodeId[%llu]", node.GetId()); |
| @@ -1328,6 +1348,7 @@ void RSUniRenderVisitor::QuickPrepareSurfaceRenderNode(RSSurfaceRenderNode& node | |||
| 1328 | RSSpecialLayerUtils::DealWithSpecialLayer(node, *curLogicalDisplayNode_, needCalcScreenSpecialLayer); | 1348 | RSSpecialLayerUtils::DealWithSpecialLayer(node, *curLogicalDisplayNode_, needCalcScreenSpecialLayer); |
| 1329 | // avoid cross node subtree visited twice or more | 1349 | // avoid cross node subtree visited twice or more |
| 1330 | if (CheckSkipAndPrepareForCrossNode(node)) { | 1350 | if (CheckSkipAndPrepareForCrossNode(node)) { |
| 1351 | + CollectHwcAndFilterNodesForCrossNode(node, isParentPrepareInReverseOrder); | ||
为啥没加到hwcVisitor里? ![]() ![]() | |||
| 1331 | return; | 1352 | return; |
| 1332 | } | 1353 | } |
| 1333 | // 0. init curSurface info and check node info | 1354 | // 0. init curSurface info and check node info |
| @@ -177,6 +177,8 @@ private: | |||
| 177 | void CollectHwcAndFilterNodesInSkippedSubTree(RSRenderNode& node); | 177 | void CollectHwcAndFilterNodesInSkippedSubTree(RSRenderNode& node); |
| 178 | void CollectHwcAndFilterNodesToParent(RSRenderNode& node, bool isParentPrepareInReverseOrder = false, | 178 | void CollectHwcAndFilterNodesToParent(RSRenderNode& node, bool isParentPrepareInReverseOrder = false, |
| 179 | bool isBlendNeedFilter = false); | 179 | bool isBlendNeedFilter = false); |
| 180 | + // Propagate the cross-node subtree's selfDrawing/filter nodes to the parent when its traversal is skipped. | ||
| 181 | + void CollectHwcAndFilterNodesForCrossNode(RSSurfaceRenderNode& node, bool isParentPrepareInReverseOrder = false); | ||
| 180 | // restore node's flag and filter dirty collection | 182 | // restore node's flag and filter dirty collection |
| 181 | void PostPrepare(RSRenderNode& node, bool isParentPrepareInReverseOrder = false, bool subTreeSkipped = false); | 183 | void PostPrepare(RSRenderNode& node, bool isParentPrepareInReverseOrder = false, bool subTreeSkipped = false); |
| 182 | void UpdateNodeVisibleRegion(RSSurfaceRenderNode& node); | 184 | void UpdateNodeVisibleRegion(RSSurfaceRenderNode& node); |
| @@ -11227,6 +11227,239 @@ HWTEST_F(RSUniRenderVisitorTest, QuickPrepareProtectiveSolidRenderNode006, TestS | |||
| 11227 | EXPECT_FLOAT_EQ(layerInfo.alpha, 0.8f); | 11227 | EXPECT_FLOAT_EQ(layerInfo.alpha, 0.8f); |
| 11228 | } | 11228 | } |
| 11229 | 11229 | ||
| 11230 | + | ||
| 11231 | +/** | ||
| 11232 | + * @tc.name: CollectHwcAndFilterNodesForCrossNode001 | ||
| 11233 | + * @tc.desc: Clone cross-node with a valid source mirrors the source's aggregated node list into | ||
| 11234 | + * itself and propagates it to the parent; the parent ends up holding both source subtree | ||
| 11235 | + * nodes and the clone self when the clone is hardware-enabled. | ||
| 11236 | + * @tc.type: FUNC | ||
| 11237 | + */ | ||
| 11238 | +HWTEST_F(RSUniRenderVisitorTest, CollectHwcAndFilterNodesForCrossNode001, TestSize.Level1) | ||
| 11239 | +{ | ||
| 11240 | + auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>(); | ||
| 11241 | + ASSERT_NE(rsUniRenderVisitor, nullptr); | ||
| 11242 | + | ||
| 11243 | + // Source cross-node: carries one hardware-enabled child node aggregated in its list. | ||
| 11244 | + auto sourceNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11245 | + ASSERT_NE(sourceNode, nullptr); | ||
| 11246 | + sourceNode->isCrossNode_ = true; | ||
| 11247 | + auto sourceChild = RSTestUtil::CreateSurfaceNode(); | ||
| 11248 | + ASSERT_NE(sourceChild, nullptr); | ||
| 11249 | + sourceChild->isHardwareEnabledNode_ = true; | ||
| 11250 | + sourceChild->nodeType_ = RSSurfaceNodeType::SELF_DRAWING_NODE; | ||
| 11251 | + sourceNode->ClearAllHwcNodeAndFilterNode(); | ||
| 11252 | + sourceNode->GetAllHwcNodeAndFilterNode().push_back(sourceChild); | ||
| 11253 | + | ||
| 11254 | + // Clone cross-node referencing the source; it is hardware-enabled so it will also insert itself. | ||
| 11255 | + auto cloneNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11256 | + ASSERT_NE(cloneNode, nullptr); | ||
| 11257 | + cloneNode->isCrossNode_ = true; | ||
| 11258 | + cloneNode->isCloneCrossNode_ = true; | ||
| 11259 | + cloneNode->sourceCrossNode_ = sourceNode; | ||
| 11260 | + cloneNode->isHardwareEnabledNode_ = true; | ||
| 11261 | + cloneNode->nodeType_ = RSSurfaceNodeType::SELF_DRAWING_NODE; | ||
| 11262 | + // Pre-populate stale data to verify the rebuild clears it. | ||
| 11263 | + auto staleNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11264 | + cloneNode->GetAllHwcNodeAndFilterNode().push_back(staleNode); | ||
| 11265 | + ASSERT_EQ(cloneNode->GetAllHwcNodeAndFilterNode().size(), 1u); | ||
| 11266 | + | ||
| 11267 | + // Parent surface node so collection has somewhere to propagate. | ||
| 11268 | + auto parent = RSTestUtil::CreateSurfaceNode(); | ||
| 11269 | + ASSERT_NE(parent, nullptr); | ||
| 11270 | + parent->AddChild(cloneNode, -1); | ||
| 11271 | + ASSERT_FALSE(cloneNode->GetParent().expired()); | ||
| 11272 | + | ||
| 11273 | + // curScreenNode_ with a different id from cloneNode so the collection guard passes. | ||
| 11274 | + auto rsContext = std::make_shared<RSContext>(); | ||
| 11275 | + rsUniRenderVisitor->curScreenNode_ = std::make_shared<RSScreenRenderNode>(1000, 0, rsContext); | ||
| 11276 | + ASSERT_NE(rsUniRenderVisitor->curScreenNode_, nullptr); | ||
| 11277 | + ASSERT_NE(rsUniRenderVisitor->curScreenNode_->GetId(), cloneNode->GetId()); | ||
| 11278 | + | ||
| 11279 | + rsUniRenderVisitor->CollectHwcAndFilterNodesForCrossNode(*cloneNode, false); | ||
| 11280 | + | ||
| 11281 | + // Clone list now holds the clone self at the front (self-inserted by | ||
| 11282 | + // CollectHwcAndFilterNodesToParent because the clone is hardware-enabled) followed by the | ||
| 11283 | + // mirrored source child; the stale entry was cleared. | ||
| 11284 | + ASSERT_EQ(cloneNode->GetAllHwcNodeAndFilterNode().size(), 2u); | ||
| 11285 | + auto cloneFront = cloneNode->GetAllHwcNodeAndFilterNode()[0].lock(); | ||
| 11286 | + auto cloneSecond = cloneNode->GetAllHwcNodeAndFilterNode()[1].lock(); | ||
| 11287 | + ASSERT_NE(cloneFront, nullptr); | ||
| 11288 | + ASSERT_NE(cloneSecond, nullptr); | ||
| 11289 | + EXPECT_EQ(cloneFront->GetId(), cloneNode->GetId()); | ||
| 11290 | + EXPECT_EQ(cloneSecond->GetId(), sourceChild->GetId()); | ||
| 11291 | + | ||
| 11292 | + // Parent holds the same entries, appended in forward order. | ||
| 11293 | + ASSERT_EQ(parent->GetAllHwcNodeAndFilterNode().size(), 2u); | ||
| 11294 | + auto parentFirst = parent->GetAllHwcNodeAndFilterNode()[0].lock(); | ||
| 11295 | + auto parentSecond = parent->GetAllHwcNodeAndFilterNode()[1].lock(); | ||
| 11296 | + ASSERT_NE(parentFirst, nullptr); | ||
| 11297 | + ASSERT_NE(parentSecond, nullptr); | ||
| 11298 | + EXPECT_EQ(parentFirst->GetId(), cloneNode->GetId()); | ||
| 11299 | + EXPECT_EQ(parentSecond->GetId(), sourceChild->GetId()); | ||
| 11300 | +} | ||
| 11301 | + | ||
| 11302 | +/** | ||
| 11303 | + * @tc.name: CollectHwcAndFilterNodesForCrossNode002 | ||
| 11304 | + * @tc.desc: Clone cross-node whose source cannot be resolved (error case) clears any stale data and | ||
| 11305 | + * does not propagate stale entries to the parent. | ||
| 11306 | + * @tc.type: FUNC | ||
| 11307 | + */ | ||
| 11308 | +HWTEST_F(RSUniRenderVisitorTest, CollectHwcAndFilterNodesForCrossNode002, TestSize.Level1) | ||
| 11309 | +{ | ||
| 11310 | + auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>(); | ||
| 11311 | + ASSERT_NE(rsUniRenderVisitor, nullptr); | ||
| 11312 | + | ||
| 11313 | + auto cloneNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11314 | + ASSERT_NE(cloneNode, nullptr); | ||
| 11315 | + cloneNode->isCrossNode_ = true; | ||
| 11316 | + cloneNode->isCloneCrossNode_ = true; | ||
| 11317 | + // sourceCrossNode_ intentionally left empty to simulate the error case. | ||
| 11318 | + auto staleNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11319 | + cloneNode->GetAllHwcNodeAndFilterNode().push_back(staleNode); | ||
| 11320 | + ASSERT_EQ(cloneNode->GetAllHwcNodeAndFilterNode().size(), 1u); | ||
| 11321 | + | ||
| 11322 | + auto parent = RSTestUtil::CreateSurfaceNode(); | ||
| 11323 | + ASSERT_NE(parent, nullptr); | ||
| 11324 | + parent->AddChild(cloneNode, -1); | ||
| 11325 | + | ||
| 11326 | + auto rsContext = std::make_shared<RSContext>(); | ||
| 11327 | + rsUniRenderVisitor->curScreenNode_ = std::make_shared<RSScreenRenderNode>(1001, 0, rsContext); | ||
| 11328 | + ASSERT_NE(rsUniRenderVisitor->curScreenNode_, nullptr); | ||
| 11329 | + | ||
| 11330 | + rsUniRenderVisitor->CollectHwcAndFilterNodesForCrossNode(*cloneNode, false); | ||
| 11331 | + | ||
| 11332 | + // Clone list cleared; clone is not hardware-enabled so nothing is inserted back. | ||
| 11333 | + EXPECT_EQ(cloneNode->GetAllHwcNodeAndFilterNode().size(), 0u); | ||
| 11334 | + EXPECT_EQ(parent->GetAllHwcNodeAndFilterNode().size(), 0u); | ||
| 11335 | +} | ||
| 11336 | + | ||
| 11337 | +/** | ||
| 11338 | + * @tc.name: CollectHwcAndFilterNodesForCrossNode003 | ||
| 11339 | + * @tc.desc: Source cross-node (not a clone) keeps its existing aggregated list untouched and just | ||
| 11340 | + * propagates it to the parent; its own contents are neither cleared nor rebuilt. | ||
| 11341 | + * @tc.type: FUNC | ||
| 11342 | + */ | ||
| 11343 | +HWTEST_F(RSUniRenderVisitorTest, CollectHwcAndFilterNodesForCrossNode003, TestSize.Level1) | ||
| 11344 | +{ | ||
| 11345 | + auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>(); | ||
| 11346 | + ASSERT_NE(rsUniRenderVisitor, nullptr); | ||
| 11347 | + | ||
| 11348 | + // Source cross-node already holds a hardware-enabled child aggregated during the first-visit prepare. | ||
| 11349 | + auto sourceNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11350 | + ASSERT_NE(sourceNode, nullptr); | ||
| 11351 | + sourceNode->isCrossNode_ = true; | ||
| 11352 | + auto sourceChild = RSTestUtil::CreateSurfaceNode(); | ||
| 11353 | + ASSERT_NE(sourceChild, nullptr); | ||
| 11354 | + sourceChild->isHardwareEnabledNode_ = true; | ||
| 11355 | + sourceChild->nodeType_ = RSSurfaceNodeType::SELF_DRAWING_NODE; | ||
| 11356 | + sourceNode->GetAllHwcNodeAndFilterNode().push_back(sourceChild); | ||
| 11357 | + ASSERT_EQ(sourceNode->GetAllHwcNodeAndFilterNode().size(), 1u); | ||
| 11358 | + | ||
| 11359 | + auto parent = RSTestUtil::CreateSurfaceNode(); | ||
| 11360 | + ASSERT_NE(parent, nullptr); | ||
| 11361 | + parent->AddChild(sourceNode, -1); | ||
| 11362 | + | ||
| 11363 | + auto rsContext = std::make_shared<RSContext>(); | ||
| 11364 | + rsUniRenderVisitor->curScreenNode_ = std::make_shared<RSScreenRenderNode>(1002, 0, rsContext); | ||
| 11365 | + ASSERT_NE(rsUniRenderVisitor->curScreenNode_, nullptr); | ||
| 11366 | + ASSERT_NE(rsUniRenderVisitor->curScreenNode_->GetId(), sourceNode->GetId()); | ||
| 11367 | + | ||
| 11368 | + rsUniRenderVisitor->CollectHwcAndFilterNodesForCrossNode(*sourceNode, true); | ||
| 11369 | + | ||
| 11370 | + // Source list is preserved as-is (not cleared, not rebuilt). | ||
| 11371 | + ASSERT_EQ(sourceNode->GetAllHwcNodeAndFilterNode().size(), 1u); | ||
| 11372 | + auto preservedChild = sourceNode->GetAllHwcNodeAndFilterNode().front().lock(); | ||
| 11373 | + ASSERT_NE(preservedChild, nullptr); | ||
| 11374 | + EXPECT_EQ(preservedChild->GetId(), sourceChild->GetId()); | ||
| 11375 | + | ||
| 11376 | + // Parent receives the source child in reverse-order insertion (front), source itself not added | ||
| 11377 | + // because it is not hardware-enabled. | ||
| 11378 | + ASSERT_EQ(parent->GetAllHwcNodeAndFilterNode().size(), 1u); | ||
| 11379 | + auto parentChild = parent->GetAllHwcNodeAndFilterNode().front().lock(); | ||
| 11380 | + ASSERT_NE(parentChild, nullptr); | ||
| 11381 | + EXPECT_EQ(parentChild->GetId(), sourceChild->GetId()); | ||
| 11382 | +} | ||
| 11383 | + | ||
| 11384 | +/** | ||
| 11385 | + * @tc.name: CollectHwcAndFilterNodesForCrossNode004 | ||
| 11386 | + * @tc.desc: When curScreenNode_ is null the collection guard skips CollectHwcAndFilterNodesToParent; | ||
| 11387 | + * the clone list rebuild still runs but nothing is propagated upward. | ||
| 11388 | + * @tc.type: FUNC | ||
| 11389 | + */ | ||
| 11390 | +HWTEST_F(RSUniRenderVisitorTest, CollectHwcAndFilterNodesForCrossNode004, TestSize.Level1) | ||
| 11391 | +{ | ||
| 11392 | + auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>(); | ||
| 11393 | + ASSERT_NE(rsUniRenderVisitor, nullptr); | ||
| 11394 | + ASSERT_EQ(rsUniRenderVisitor->curScreenNode_, nullptr); | ||
| 11395 | + | ||
| 11396 | + auto sourceNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11397 | + ASSERT_NE(sourceNode, nullptr); | ||
| 11398 | + sourceNode->isCrossNode_ = true; | ||
| 11399 | + auto sourceChild = RSTestUtil::CreateSurfaceNode(); | ||
| 11400 | + ASSERT_NE(sourceChild, nullptr); | ||
| 11401 | + sourceChild->isHardwareEnabledNode_ = true; | ||
| 11402 | + sourceChild->nodeType_ = RSSurfaceNodeType::SELF_DRAWING_NODE; | ||
| 11403 | + sourceNode->GetAllHwcNodeAndFilterNode().push_back(sourceChild); | ||
| 11404 | + | ||
| 11405 | + auto cloneNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11406 | + ASSERT_NE(cloneNode, nullptr); | ||
| 11407 | + cloneNode->isCrossNode_ = true; | ||
| 11408 | + cloneNode->isCloneCrossNode_ = true; | ||
| 11409 | + cloneNode->sourceCrossNode_ = sourceNode; | ||
| 11410 | + | ||
| 11411 | + auto parent = RSTestUtil::CreateSurfaceNode(); | ||
| 11412 | + ASSERT_NE(parent, nullptr); | ||
| 11413 | + parent->AddChild(cloneNode, -1); | ||
| 11414 | + ASSERT_EQ(parent->GetAllHwcNodeAndFilterNode().size(), 0u); | ||
| 11415 | + | ||
| 11416 | + rsUniRenderVisitor->CollectHwcAndFilterNodesForCrossNode(*cloneNode, false); | ||
| 11417 | + | ||
| 11418 | + // Clone list rebuild happened; parent propagation skipped because curScreenNode_ is null. | ||
| 11419 | + ASSERT_EQ(cloneNode->GetAllHwcNodeAndFilterNode().size(), 1u); | ||
| 11420 | + EXPECT_EQ(parent->GetAllHwcNodeAndFilterNode().size(), 0u); | ||
| 11421 | +} | ||
| 11422 | + | ||
| 11423 | +/** | ||
| 11424 | + * @tc.name: CollectHwcAndFilterNodesForCrossNode005 | ||
| 11425 | + * @tc.desc: When the node itself is the current screen root (same id) the collection guard skips | ||
| 11426 | + * propagation to a non-existent parent, while the clone list rebuild still runs. | ||
| 11427 | + * @tc.type: FUNC | ||
| 11428 | + */ | ||
| 11429 | +HWTEST_F(RSUniRenderVisitorTest, CollectHwcAndFilterNodesForCrossNode005, TestSize.Level1) | ||
| 11430 | +{ | ||
| 11431 | + auto rsUniRenderVisitor = std::make_shared<RSUniRenderVisitor>(); | ||
| 11432 | + ASSERT_NE(rsUniRenderVisitor, nullptr); | ||
| 11433 | + | ||
| 11434 | + auto sourceNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11435 | + ASSERT_NE(sourceNode, nullptr); | ||
| 11436 | + sourceNode->isCrossNode_ = true; | ||
| 11437 | + auto sourceChild = RSTestUtil::CreateSurfaceNode(); | ||
| 11438 | + ASSERT_NE(sourceChild, nullptr); | ||
| 11439 | + sourceChild->isHardwareEnabledNode_ = true; | ||
| 11440 | + sourceChild->nodeType_ = RSSurfaceNodeType::SELF_DRAWING_NODE; | ||
| 11441 | + sourceNode->GetAllHwcNodeAndFilterNode().push_back(sourceChild); | ||
| 11442 | + | ||
| 11443 | + auto cloneNode = RSTestUtil::CreateSurfaceNode(); | ||
| 11444 | + ASSERT_NE(cloneNode, nullptr); | ||
| 11445 | + cloneNode->isCrossNode_ = true; | ||
| 11446 | + cloneNode->isCloneCrossNode_ = true; | ||
| 11447 | + cloneNode->sourceCrossNode_ = sourceNode; | ||
| 11448 | + | ||
| 11449 | + // Make curScreenNode_ share the clone id to hit the skip-collection guard. | ||
| 11450 | + auto rsContext = std::make_shared<RSContext>(); | ||
| 11451 | + rsUniRenderVisitor->curScreenNode_ = std::make_shared<RSScreenRenderNode>(cloneNode->GetId(), 0, rsContext); | ||
| 11452 | + ASSERT_EQ(rsUniRenderVisitor->curScreenNode_->GetId(), cloneNode->GetId()); | ||
| 11453 | + | ||
| 11454 | + rsUniRenderVisitor->CollectHwcAndFilterNodesForCrossNode(*cloneNode, false); | ||
| 11455 | + | ||
| 11456 | + // Rebuild of the clone list still happened; no parent to propagate to in this config. | ||
| 11457 | + ASSERT_EQ(cloneNode->GetAllHwcNodeAndFilterNode().size(), 1u); | ||
| 11458 | + auto mirrored = cloneNode->GetAllHwcNodeAndFilterNode().front().lock(); | ||
| 11459 | + ASSERT_NE(mirrored, nullptr); | ||
| 11460 | + EXPECT_EQ(mirrored->GetId(), sourceChild->GetId()); | ||
| 11461 | +} | ||
| 11462 | + | ||
| 11230 | /** | 11463 | /** |
| 11231 | * @tc.name: CollectVirtualScreenNodeId_ManagerNull | 11464 | * @tc.name: CollectVirtualScreenNodeId_ManagerNull |
| 11232 | * @tc.desc: Test CollectVirtualScreenNodeId when virtualScreenParallelManager_ is nullptr | 11465 | * @tc.desc: Test CollectVirtualScreenNodeId when virtualScreenParallelManager_ is nullptr |


cloneNodeList 作用