• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "foundation/graphic/graphic_2d/utils/log/rs_trace.h"
17 #include "rs_profiler.h"
18 #include "rs_profiler_json.h"
19 #include "rs_profiler_network.h"
20 
21 #include "common/rs_obj_geometry.h"
22 #include "pipeline/rs_context.h"
23 #include "pipeline/rs_display_render_node.h"
24 #include "pipeline/rs_root_render_node.h"
25 #include "pipeline/rs_surface_handler.h"
26 #include "pipeline/rs_surface_render_node.h"
27 
28 namespace OHOS::Rosen {
29 
DumpNode(const RSRenderNode & node,JsonWriter & out)30 void RSProfiler::DumpNode(const RSRenderNode& node, JsonWriter& out)
31 {
32     out.PushObject();
33     DumpNodeBaseInfo(node, out);
34     DumpNodeProperties(node.GetRenderProperties(), out);
35     DumpNodeOptionalFlags(node, out);
36     DumpNodeDrawCmdModifiers(node, out);
37     DumpNodeAnimations(node.animationManager_, out);
38     DumpNodeChildrenListUpdate(node, out);
39 
40     auto& children = out["children"];
41     children.PushArray();
42     if (node.GetSortedChildren()) {
43         for (auto& child : *node.GetSortedChildren()) {
44             if (child) {
45                 DumpNode(*child, children);
46             }
47         }
48     }
49     children.PopArray();
50     out.PopObject();
51 }
52 
DumpNodeBaseInfo(const RSRenderNode & node,JsonWriter & out)53 void RSProfiler::DumpNodeBaseInfo(const RSRenderNode& node, JsonWriter& out)
54 {
55     std::string type;
56     node.DumpNodeType(node.GetType(), type);
57     out["type"] = type;
58     out["id"] = node.GetId();
59     out["instanceRootNodeId"] = node.GetInstanceRootNodeId();
60     DumpNodeSubsurfaces(node, out);
61     auto sharedTrans = node.GetSharedTransitionParam();
62     if (sharedTrans) {
63         out["SharedTransitionParam"] =
64             std::to_string(sharedTrans->inNodeId_) + " -> " + std::to_string(sharedTrans->outNodeId_);
65     }
66     if (node.IsSuggestedDrawInGroup()) {
67         out["nodeGroup"] = static_cast<int>(node.nodeGroupType_);
68     }
69     if (node.GetUifirstRootNodeId() != INVALID_NODEID) {
70         out["uifirstRootNodeId"] = node.GetUifirstRootNodeId();
71     }
72     DumpNodeSubClassNode(node, out);
73 }
74 
DumpNodeSubsurfaces(const RSRenderNode & node,JsonWriter & out)75 void RSProfiler::DumpNodeSubsurfaces(const RSRenderNode& node, JsonWriter& out)
76 {
77     if (auto surface = node.ReinterpretCastTo<RSSurfaceRenderNode>(); surface && surface->HasSubSurfaceNodes()) {
78         auto& subsurface = out["subsurface"];
79         subsurface.PushArray();
80         for (auto [id, _] : surface->GetChildSubSurfaceNodes()) {
81             subsurface.Append(id);
82         }
83         subsurface.PopArray();
84     }
85 }
86 
DumpNodeSubClassNode(const RSRenderNode & node,JsonWriter & out)87 void RSProfiler::DumpNodeSubClassNode(const RSRenderNode& node, JsonWriter& out)
88 {
89     auto& subclass = out["subclass"];
90     subclass.PushObject();
91     if (node.GetType() == RSRenderNodeType::SURFACE_NODE) {
92         auto& surfaceNode = static_cast<const RSSurfaceRenderNode&>(node);
93         auto p = node.parent_.lock();
94         subclass["Parent"] = p ? p->GetId() : uint64_t(0);
95         subclass["Name"] = surfaceNode.GetName();
96         out["hasConsumer"] = surfaceNode.GetRSSurfaceHandler()->HasConsumer();
97         std::string contextAlpha = std::to_string(surfaceNode.contextAlpha_);
98         std::string propertyAlpha = std::to_string(surfaceNode.GetRenderProperties().GetAlpha());
99         subclass["Alpha"] = propertyAlpha + " (include ContextAlpha: " + contextAlpha + ")";
100         subclass["Visible"] = std::to_string(surfaceNode.GetRenderProperties().GetVisible()) + " " +
101                               surfaceNode.GetVisibleRegion().GetRegionInfo();
102         subclass["Opaque"] = surfaceNode.GetOpaqueRegion().GetRegionInfo();
103         subclass["OcclusionBg"] = std::to_string((surfaceNode.GetAbilityBgAlpha()));
104         subclass["SecurityLayer"] = surfaceNode.GetSecurityLayer();
105         subclass["skipLayer"] = surfaceNode.GetSkipLayer();
106     } else if (node.GetType() == RSRenderNodeType::ROOT_NODE) {
107         auto& rootNode = static_cast<const RSRootRenderNode&>(node);
108         subclass["Visible"] = rootNode.GetRenderProperties().GetVisible();
109         subclass["Size"] = { rootNode.GetRenderProperties().GetFrameWidth(),
110             rootNode.GetRenderProperties().GetFrameHeight() };
111         subclass["EnableRender"] = rootNode.GetEnableRender();
112     } else if (node.GetType() == RSRenderNodeType::DISPLAY_NODE) {
113         auto& displayNode = static_cast<const RSDisplayRenderNode&>(node);
114         subclass["skipLayer"] = displayNode.GetSecurityDisplay();
115     }
116     subclass.PopObject();
117 }
118 
DumpNodeOptionalFlags(const RSRenderNode & node,JsonWriter & out)119 void RSProfiler::DumpNodeOptionalFlags(const RSRenderNode& node, JsonWriter& out)
120 {
121     if (node.GetBootAnimation()) {
122         out["GetBootAnimation"] = true;
123     }
124     if (node.isContainBootAnimation_) {
125         out["isContainBootAnimation_"] = true;
126     }
127     if (node.dirtyStatus_ != RSRenderNode::NodeDirty::CLEAN) {
128         out["isNodeDirty"] = static_cast<int>(node.dirtyStatus_);
129     }
130     if (node.GetRenderProperties().IsDirty()) {
131         out["isPropertyDirty"] = true;
132     }
133     if (node.isSubTreeDirty_) {
134         out["isSubTreeDirty"] = true;
135     }
136     if (node.IsPureContainer()) {
137         out["IsPureContainer"] = true;
138     }
139 }
140 
DumpNodeDrawCmdModifiers(const RSRenderNode & node,JsonWriter & out)141 void RSProfiler::DumpNodeDrawCmdModifiers(const RSRenderNode& node, JsonWriter& out)
142 {
143     if (!node.renderContent_) {
144         return;
145     }
146 
147     auto& modifiersJson = out["DrawCmdModifiers"];
148     modifiersJson.PushArray();
149     for (auto& [type, modifiers] : node.renderContent_->drawCmdModifiers_) {
150         modifiersJson.PushObject();
151         modifiersJson["type"] = static_cast<int>(type);
152         auto& modifierDesc = modifiersJson["modifiers"];
153         modifierDesc.PushArray();
154         for (const auto& modifier : modifiers) {
155             if (modifier) {
156                 DumpNodeDrawCmdModifier(node, modifierDesc, static_cast<int>(type), *modifier);
157             }
158         }
159         modifiersJson.PopArray();
160         modifiersJson.PopObject();
161     }
162     modifiersJson.PopArray();
163 }
164 
Hex(uint32_t value)165 static std::string Hex(uint32_t value)
166 {
167     std::stringstream sstream;
168     sstream << std::hex << value;
169     return sstream.str();
170 }
171 
DumpNodeDrawCmdModifier(const RSRenderNode & node,JsonWriter & out,int type,RSRenderModifier & modifier)172 void RSProfiler::DumpNodeDrawCmdModifier(
173     const RSRenderNode& node, JsonWriter& out, int type, RSRenderModifier& modifier)
174 {
175     auto modType = static_cast<RSModifierType>(type);
176 
177     if (modType < RSModifierType::ENV_FOREGROUND_COLOR) {
178         auto propertyPtr = std::static_pointer_cast<RSRenderProperty<Drawing::DrawCmdListPtr>>(modifier.GetProperty());
179         auto drawCmdListPtr = propertyPtr ? propertyPtr->Get() : nullptr;
180         auto propertyStr = drawCmdListPtr ? drawCmdListPtr->GetOpsWithDesc() : "";
181         size_t pos = 0;
182         size_t oldpos = 0;
183 
184         out.PushObject();
185         auto& property = out["drawCmdList"];
186         property.PushArray();
187         while ((pos = propertyStr.find('\n', oldpos)) != std::string::npos) {
188             property.Append(propertyStr.substr(oldpos, pos - oldpos));
189             oldpos = pos + 1;
190         }
191         property.PopArray();
192         out.PopObject();
193     } else if (modType == RSModifierType::ENV_FOREGROUND_COLOR) {
194         auto propertyPtr = std::static_pointer_cast<RSRenderAnimatableProperty<Color>>(modifier.GetProperty());
195         if (propertyPtr) {
196             out.PushObject();
197             out["ENV_FOREGROUND_COLOR"] = "#" + Hex(propertyPtr->Get().AsRgbaInt()) + " (RGBA)";
198             out.PopObject();
199         }
200     } else if (modType == RSModifierType::ENV_FOREGROUND_COLOR_STRATEGY) {
201         auto propertyPtr =
202             std::static_pointer_cast<RSRenderProperty<ForegroundColorStrategyType>>(modifier.GetProperty());
203         if (propertyPtr) {
204             out.PushObject();
205             out["ENV_FOREGROUND_COLOR_STRATEGY"] = static_cast<int>(propertyPtr->Get());
206             out.PopObject();
207         }
208     } else if (modType == RSModifierType::GEOMETRYTRANS) {
209         auto propertyPtr = std::static_pointer_cast<RSRenderProperty<SkMatrix>>(modifier.GetProperty());
210         if (propertyPtr) {
211             std::string str;
212             propertyPtr->Get().dump(str, 0);
213             out.PushObject();
214             out["GEOMETRYTRANS"] = str;
215             out.PopObject();
216         }
217     }
218 }
219 
DumpNodeProperties(const RSProperties & properties,JsonWriter & out)220 void RSProfiler::DumpNodeProperties(const RSProperties& properties, JsonWriter& out)
221 {
222     auto& json = out["Properties"];
223     json.PushObject();
224     json["Bounds"] = { properties.GetBoundsPositionX(), properties.GetBoundsPositionY(), properties.GetBoundsWidth(),
225         properties.GetBoundsHeight() };
226     json["Frame"] = { properties.GetFramePositionX(), properties.GetFramePositionY(), properties.GetFrameWidth(),
227         properties.GetFrameHeight() };
228 
229     if (!properties.GetVisible()) {
230         json["IsVisible"] = false;
231     }
232     DumpNodePropertiesClip(properties, json);
233     DumpNodePropertiesTransform(properties, json);
234     DumpNodePropertiesDecoration(properties, json);
235     DumpNodePropertiesShadow(properties, json);
236     DumpNodePropertiesEffects(properties, json);
237     DumpNodePropertiesColor(properties, json);
238     json.PopObject();
239 }
240 
DumpNodePropertiesClip(const RSProperties & properties,JsonWriter & out)241 void RSProfiler::DumpNodePropertiesClip(const RSProperties& properties, JsonWriter& out)
242 {
243     if (properties.clipToBounds_) {
244         out["ClipToBounds"] = true;
245     }
246     if (properties.clipToFrame_) {
247         out["ClipToFrame"] = true;
248     }
249 }
250 
DumpNodePropertiesTransform(const RSProperties & properties,JsonWriter & out)251 void RSProfiler::DumpNodePropertiesTransform(const RSProperties& properties, JsonWriter& out)
252 {
253     if (!ROSEN_EQ(properties.GetPositionZ(), 0.f)) {
254         out["PositionZ"] = properties.GetPositionZ();
255     }
256     RSTransform defaultTransform;
257     Vector2f pivot = properties.GetPivot();
258     if ((!ROSEN_EQ(pivot[0], defaultTransform.pivotX_) || !ROSEN_EQ(pivot[1], defaultTransform.pivotY_))) {
259         out["Pivot"] = { pivot[0], pivot[1] };
260     }
261     if (!ROSEN_EQ(properties.GetRotation(), defaultTransform.rotation_)) {
262         out["Rotation"] = properties.GetRotation();
263     }
264     if (!ROSEN_EQ(properties.GetRotationX(), defaultTransform.rotationX_)) {
265         out["RotationX"] = properties.GetRotationX();
266     }
267     if (!ROSEN_EQ(properties.GetRotationY(), defaultTransform.rotationY_)) {
268         out["RotationY"] = properties.GetRotationY();
269     }
270     if (!ROSEN_EQ(properties.GetTranslateX(), defaultTransform.translateX_)) {
271         out["TranslateX"] = properties.GetTranslateX();
272     }
273     if (!ROSEN_EQ(properties.GetTranslateY(), defaultTransform.translateY_)) {
274         out["TranslateY"] = properties.GetTranslateY();
275     }
276     if (!ROSEN_EQ(properties.GetTranslateZ(), defaultTransform.translateZ_)) {
277         out["TranslateZ"] = properties.GetTranslateZ();
278     }
279     if (!ROSEN_EQ(properties.GetScaleX(), defaultTransform.scaleX_)) {
280         out["ScaleX"] = properties.GetScaleX();
281     }
282     if (!ROSEN_EQ(properties.GetScaleY(), defaultTransform.scaleY_)) {
283         out["ScaleY"] = properties.GetScaleY();
284     }
285 }
286 
DumpNodePropertiesDecoration(const RSProperties & properties,JsonWriter & out)287 void RSProfiler::DumpNodePropertiesDecoration(const RSProperties& properties, JsonWriter& out)
288 {
289     if (!properties.GetCornerRadius().IsZero()) {
290         out["CornerRadius"] = { properties.GetCornerRadius().x_, properties.GetCornerRadius().y_,
291             properties.GetCornerRadius().z_, properties.GetCornerRadius().w_ };
292     }
293     if (properties.pixelStretch_.has_value()) {
294         auto& pixelStretch = out["PixelStretch"];
295         pixelStretch.PushObject();
296         pixelStretch["left"] = properties.pixelStretch_->z_;
297         pixelStretch["top"] = properties.pixelStretch_->y_;
298         pixelStretch["right"] = properties.pixelStretch_->z_;
299         pixelStretch["bottom"] = properties.pixelStretch_->w_;
300         pixelStretch.PopObject();
301     }
302     if (!ROSEN_EQ(properties.GetAlpha(), 1.f)) {
303         out["Alpha"] = properties.GetAlpha();
304     }
305     if (!ROSEN_EQ(properties.GetSpherize(), 0.f)) {
306         out["Spherize"] = properties.GetSpherize();
307     }
308 
309     if (!ROSEN_EQ(properties.GetForegroundColor(), RgbPalette::Transparent())) {
310         out["ForegroundColor"] = "#" + Hex(properties.GetForegroundColor().AsArgbInt()) + " (ARGB)";
311     }
312     if (!ROSEN_EQ(properties.GetBackgroundColor(), RgbPalette::Transparent())) {
313         out["BackgroundColor"] = "#" + Hex(properties.GetBackgroundColor().AsArgbInt()) + " (ARGB)";
314     }
315     Decoration defaultDecoration;
316     if ((!ROSEN_EQ(properties.GetBgImagePositionX(), defaultDecoration.bgImageRect_.left_) ||
317         !ROSEN_EQ(properties.GetBgImagePositionY(), defaultDecoration.bgImageRect_.top_) ||
318         !ROSEN_EQ(properties.GetBgImageWidth(), defaultDecoration.bgImageRect_.width_) ||
319         !ROSEN_EQ(properties.GetBgImageHeight(), defaultDecoration.bgImageRect_.height_))) {
320         out["BgImage"] = { properties.GetBgImagePositionX(), properties.GetBgImagePositionY(),
321             properties.GetBgImageWidth(), properties.GetBgImageHeight() };
322     }
323 }
324 
DumpNodePropertiesShadow(const RSProperties & properties,JsonWriter & out)325 void RSProfiler::DumpNodePropertiesShadow(const RSProperties& properties, JsonWriter& out)
326 {
327     if (!ROSEN_EQ(properties.GetShadowColor(), Color(DEFAULT_SPOT_COLOR))) {
328         out["ShadowColor"] = "#" + Hex(properties.GetShadowColor().AsArgbInt()) + " (ARGB)";
329     }
330     if (!ROSEN_EQ(properties.GetShadowOffsetX(), DEFAULT_SHADOW_OFFSET_X)) {
331         out["ShadowOffsetX"] = properties.GetShadowOffsetX();
332     }
333     if (!ROSEN_EQ(properties.GetShadowOffsetY(), DEFAULT_SHADOW_OFFSET_Y)) {
334         out["ShadowOffsetY"] = properties.GetShadowOffsetY();
335     }
336     if (!ROSEN_EQ(properties.GetShadowAlpha(), 0.f)) {
337         out["ShadowAlpha"] = properties.GetShadowAlpha();
338     }
339     if (!ROSEN_EQ(properties.GetShadowElevation(), 0.f)) {
340         out["ShadowElevation"] = properties.GetShadowElevation();
341     }
342     if (!ROSEN_EQ(properties.GetShadowRadius(), 0.f)) {
343         out["ShadowRadius"] = properties.GetShadowRadius();
344     }
345     if (!ROSEN_EQ(properties.GetShadowIsFilled(), false)) {
346         out["ShadowIsFilled"] = properties.GetShadowIsFilled();
347     }
348 }
349 
DumpNodePropertiesEffects(const RSProperties & properties,JsonWriter & out)350 void RSProfiler::DumpNodePropertiesEffects(const RSProperties& properties, JsonWriter& out)
351 {
352     if (properties.border_ && properties.border_->HasBorder()) {
353         out["Border"] = properties.border_->ToString();
354     }
355     auto filter = properties.GetFilter();
356     if (filter && filter->IsValid()) {
357         out["Filter"] = filter->GetDescription();
358     }
359     auto backgroundFilter = properties.GetBackgroundFilter();
360     if (backgroundFilter && backgroundFilter->IsValid()) {
361         out["BackgroundFilter"] = backgroundFilter->GetDescription();
362     }
363     auto foregroundFilterCache = properties.GetForegroundFilterCache();
364     if (foregroundFilterCache && foregroundFilterCache->IsValid()) {
365         out["ForegroundFilter"] = foregroundFilterCache->GetDescription();
366     }
367     if (properties.outline_ && properties.outline_->HasBorder()) {
368         out["Outline"] = properties.outline_->ToString();
369     }
370     if (!ROSEN_EQ(properties.GetFrameGravity(), Gravity::DEFAULT)) {
371         out["FrameGravity"] = static_cast<int>(properties.GetFrameGravity());
372     }
373     if (properties.GetUseEffect()) {
374         out["GetUseEffect"] = true;
375     }
376     auto grayScale = properties.GetGrayScale();
377     if (grayScale.has_value() && !ROSEN_EQ(*grayScale, 0.f)) {
378         out["GrayScale"] = *grayScale;
379     }
380     if (!ROSEN_EQ(properties.GetLightUpEffect(), 1.f)) {
381         out["LightUpEffect"] = properties.GetLightUpEffect();
382     }
383     auto dynamicLightUpRate = properties.GetDynamicLightUpRate();
384     if (dynamicLightUpRate.has_value() && !ROSEN_EQ(*dynamicLightUpRate, 0.f)) {
385         out["DynamicLightUpRate"] = *dynamicLightUpRate;
386     }
387     auto dynamicLightUpDegree = properties.GetDynamicLightUpDegree();
388     if (dynamicLightUpDegree.has_value() && !ROSEN_EQ(*dynamicLightUpDegree, 0.f)) {
389         out["DynamicLightUpDegree"] = *dynamicLightUpDegree;
390     }
391 }
392 
DumpNodePropertiesColor(const RSProperties & properties,JsonWriter & out)393 void RSProfiler::DumpNodePropertiesColor(const RSProperties& properties, JsonWriter& out)
394 {
395     auto brightness = properties.GetBrightness();
396     if (brightness.has_value() && !ROSEN_EQ(*brightness, 1.f)) {
397         out["Brightness"] = *brightness;
398     }
399     auto contrast = properties.GetContrast();
400     if (contrast.has_value() && !ROSEN_EQ(*contrast, 1.f)) {
401         out["Contrast"] = *contrast;
402     }
403     auto saturate = properties.GetSaturate();
404     if (saturate.has_value() && !ROSEN_EQ(*saturate, 1.f)) {
405         out["Saturate"] = *saturate;
406     }
407     auto sepia = properties.GetSepia();
408     if (sepia.has_value() && !ROSEN_EQ(*sepia, 0.f)) {
409         out["Sepia"] = *sepia;
410     }
411     auto invert = properties.GetInvert();
412     if (invert.has_value() && !ROSEN_EQ(*invert, 0.f)) {
413         out["Invert"] = *invert;
414     }
415     auto hueRotate = properties.GetHueRotate();
416     if (hueRotate.has_value() && !ROSEN_EQ(*hueRotate, 0.f)) {
417         out["HueRotate"] = *hueRotate;
418     }
419     auto colorBlend = properties.GetColorBlend();
420     if (colorBlend.has_value() && !ROSEN_EQ(*colorBlend, RgbPalette::Transparent())) {
421         out["ColorBlend"] = "#" + Hex(colorBlend->AsArgbInt()) + " (ARGB)";
422     }
423     if (!ROSEN_EQ(properties.GetColorBlendMode(), 0)) {
424         out["skblendmode"] = properties.GetColorBlendMode() - 1;
425         out["blendType"] = properties.GetColorBlendApplyType();
426     }
427 }
428 
DumpNodeAnimations(const RSAnimationManager & animationManager,JsonWriter & out)429 void RSProfiler::DumpNodeAnimations(const RSAnimationManager& animationManager, JsonWriter& out)
430 {
431     if (animationManager.animations_.empty()) {
432         return;
433     }
434     auto& animations = out["RSAnimationManager"];
435     animations.PushArray();
436     for (auto [id, animation] : animationManager.animations_) {
437         if (animation) {
438             DumpNodeAnimation(*animation, animations);
439         }
440     }
441     animations.PopArray();
442 }
443 
DumpNodeAnimation(const RSRenderAnimation & animation,JsonWriter & out)444 void RSProfiler::DumpNodeAnimation(const RSRenderAnimation& animation, JsonWriter& out)
445 {
446     out.PushObject();
447     out["id"] = animation.id_;
448     std::string type;
449     animation.DumpAnimationType(type);
450     out["type"] = type;
451     out["AnimationState"] = static_cast<int>(animation.state_);
452     out["StartDelay"] = animation.animationFraction_.GetDuration();
453     out["Duration"] = animation.animationFraction_.GetStartDelay();
454     out["Speed"] = animation.animationFraction_.GetSpeed();
455     out["RepeatCount"] = animation.animationFraction_.GetRepeatCount();
456     out["AutoReverse"] = animation.animationFraction_.GetAutoReverse();
457     out["Direction"] = animation.animationFraction_.GetDirection();
458     out["FillMode"] = static_cast<int>(animation.animationFraction_.GetFillMode());
459     out["RepeatCallbackEnable"] = animation.animationFraction_.GetRepeatCallbackEnable();
460     out["FrameRateRange_min"] = animation.animationFraction_.GetFrameRateRange().min_;
461     out["FrameRateRange_max"] = animation.animationFraction_.GetFrameRateRange().max_;
462     out["FrameRateRange_prefered"] = animation.animationFraction_.GetFrameRateRange().preferred_;
463     out.PopObject();
464 }
465 
DumpNodeChildrenListUpdate(const RSRenderNode & node,JsonWriter & out)466 void RSProfiler::DumpNodeChildrenListUpdate(const RSRenderNode& node, JsonWriter& out)
467 {
468     if (!node.isFullChildrenListValid_) {
469         auto& childrenUpdate = out["children update"];
470         childrenUpdate.PushObject();
471         childrenUpdate["current count"] = node.fullChildrenList_->size();
472         std::string expected = std::to_string(node.GetSortedChildren()->size());
473         if (!node.disappearingChildren_.empty()) {
474             childrenUpdate["disappearing count"] = node.disappearingChildren_.size();
475             expected += " + " + std::to_string(node.disappearingChildren_.size());
476         }
477         childrenUpdate["expected count"] = expected;
478         childrenUpdate.PopObject();
479     }
480 }
481 
482 } // namespace OHOS::Rosen