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 "rs_profiler.h"
17 
18 #include <cstddef>
19 #include <filesystem>
20 #include <numeric>
21 
22 #include "foundation/graphic/graphic_2d/utils/log/rs_trace.h"
23 #include "rs_profiler_archive.h"
24 #include "rs_profiler_cache.h"
25 #include "rs_profiler_capture_recorder.h"
26 #include "rs_profiler_capturedata.h"
27 #include "rs_profiler_command.h"
28 #include "rs_profiler_file.h"
29 #include "rs_profiler_json.h"
30 #include "rs_profiler_log.h"
31 #include "rs_profiler_network.h"
32 #include "rs_profiler_packet.h"
33 #include "rs_profiler_settings.h"
34 #include "rs_profiler_telemetry.h"
35 
36 #include "params/rs_display_render_params.h"
37 #include "pipeline/rs_main_thread.h"
38 #include "pipeline/rs_render_service_connection.h"
39 #include "pipeline/rs_uni_render_util.h"
40 #include "render/rs_typeface_cache.h"
41 #include "pipeline/rs_render_node_gc.h"
42 
43 namespace OHOS::Rosen {
44 
45 // (user): Move to RSProfiler
46 static RSRenderService* g_renderService = nullptr;
47 static std::atomic<int32_t> g_renderServiceCpuId = 0;
48 static std::atomic<int32_t> g_renderServiceRenderCpuId = 0;
49 static RSMainThread* g_mainThread = nullptr;
50 static RSContext* g_context = nullptr;
51 static uint64_t g_frameBeginTimestamp = 0u;
52 static uint64_t g_frameRenderBeginTimestamp = 0u;
53 static double g_dirtyRegionPercentage = 0.0;
54 static bool g_rdcSent = true;
55 static uint64_t g_recordMinVsync = 0;
56 static uint64_t g_recordMaxVsync = 0;
57 
58 static std::atomic<uint32_t> g_lastCacheImageCount = 0;
59 
60 static RSFile g_recordFile {};
61 static double g_recordStartTime = 0.0;
62 static uint32_t g_frameNumber = 0;
63 
64 static RSFile g_playbackFile {};
65 static double g_playbackStartTime = 0.0;
66 static NodeId g_playbackParentNodeId = 0;
67 static int g_playbackPid = 0;
68 static bool g_playbackShouldBeTerminated = true;
69 static double g_playbackPauseTime = 0;
70 static int g_playbackWaitFrames = 0;
71 static double g_replayLastPauseTimeReported = 0;
72 
73 static std::vector<std::pair<NodeId, uint32_t>> g_nodeListPerf;
74 static std::unordered_map<NodeId, uint32_t> g_mapNode2Count;
75 static std::unordered_map<NodeId, uint32_t> g_mapNode2UpTime;
76 static std::unordered_map<NodeId, uint32_t> g_mapNode2UpDownTime;
77 static NodeId g_calcPerfNode = 0;
78 static uint32_t g_calcPerfNodeTry = 0;
79 static bool g_calcPerfNodeExcludeDown = false;
80 
81 static std::vector<std::pair<std::shared_ptr<RSRenderNode>,
82             std::vector<std::shared_ptr<RSRenderNode>>>> g_calcPerfSavedChildren;
83 static NodeId g_blinkNodeId = 0;
84 static uint32_t g_blinkNodeCount = 0;
85 static std::vector<std::shared_ptr<RSRenderNode>> g_blinkSavedParentChildren;
86 
87 constexpr int CALC_PERF_NODE_TIME_COUNT_MIN = 128; // min render tries
88 constexpr int CALC_PERF_NODE_TIME_COUNT_MAX = 4096; // max render tries
89 static uint32_t g_effectiveNodeTimeCount = CALC_PERF_NODE_TIME_COUNT_MAX;
90 static uint64_t g_calcPerfNodeTime[CALC_PERF_NODE_TIME_COUNT_MAX];
91 static int g_nodeListPerfCalcIndex = -1;
92 
93 static std::string g_testDataFrame;
94 static std::vector<RSRenderNode::SharedPtr> g_childOfDisplayNodes;
95 
96 #pragma pack(push, 1)
97 struct AlignedMessageParcel {
98     uint8_t pad = 0u;
99     MessageParcel parcel;
100 };
101 #pragma pack(pop)
102 
DeviceInfoToCaptureData(double time, const DeviceInfo& in, RSCaptureData& out)103 void DeviceInfoToCaptureData(double time, const DeviceInfo& in, RSCaptureData& out)
104 {
105     std::string frequency;
106     std::string load;
107     for (uint32_t i = 0; i < in.cpu.cores; i++) {
108         frequency += std::to_string(in.cpu.coreFrequencyLoad[i].current);
109         load += std::to_string(in.cpu.coreFrequencyLoad[i].load);
110         if (i + 1 < in.cpu.cores) {
111             frequency += ";";
112             load += ";";
113         }
114     }
115 
116     out.SetTime(static_cast<float>(time));
117     out.SetProperty(RSCaptureData::KEY_CPU_TEMP, in.cpu.temperature);
118     out.SetProperty(RSCaptureData::KEY_CPU_CURRENT, in.cpu.current);
119     out.SetProperty(RSCaptureData::KEY_CPU_LOAD, load);
120     out.SetProperty(RSCaptureData::KEY_CPU_FREQ, frequency);
121     out.SetProperty(RSCaptureData::KEY_GPU_LOAD, in.gpu.frequencyLoad.load);
122     out.SetProperty(RSCaptureData::KEY_GPU_FREQ, in.gpu.frequencyLoad.current);
123 }
124 
GetPid(const std::shared_ptr<RSRenderNode>& node)125 static pid_t GetPid(const std::shared_ptr<RSRenderNode>& node)
126 {
127     return node ? Utils::ExtractPid(node->GetId()) : 0;
128 }
129 
GetNodeId(const std::shared_ptr<RSRenderNode>& node)130 static NodeId GetNodeId(const std::shared_ptr<RSRenderNode>& node)
131 {
132     return node ? Utils::ExtractNodeId(node->GetId()) : 0;
133 }
134 
SendTelemetry(double time)135 static void SendTelemetry(double time)
136 {
137     if (time >= 0.0) {
138         RSCaptureData captureData;
139         DeviceInfoToCaptureData(time, RSTelemetry::GetDeviceInfo(), captureData);
140         Network::SendCaptureData(captureData);
141     }
142 }
143 
144 /*
145     To visualize the damage region (as it's set for KHR_partial_update), you can set the following variable:
146     'hdc shell param set rosen.dirtyregiondebug.enabled 6'
147 */
SetDirtyRegion(const Occlusion::Region& dirtyRegion)148 void RSProfiler::SetDirtyRegion(const Occlusion::Region& dirtyRegion)
149 {
150     if (!IsRecording()) {
151         return;
152     }
153 
154     const double maxPercentValue = 100.0;
155     g_dirtyRegionPercentage = maxPercentValue;
156 
157     if (!g_context) {
158         return;
159     }
160     std::shared_ptr<RSDisplayRenderNode> displayNode = GetDisplayNode(*g_context);
161     if (!displayNode) {
162         return;
163     }
164     auto params = static_cast<RSDisplayRenderParams*>(displayNode->GetRenderParams().get());
165     if (!params) {
166         return;
167     }
168 
169     auto screenInfo = params->GetScreenInfo();
170     const uint64_t displayWidth = screenInfo.width;
171     const uint64_t displayHeight = screenInfo.height;
172     const uint64_t displayArea = displayWidth * displayHeight;
173 
174     auto rects = RSUniRenderUtil::ScreenIntersectDirtyRects(dirtyRegion, screenInfo);
175     uint64_t dirtyRegionArea = 0;
176     for (const auto& rect : rects) {
177         dirtyRegionArea += static_cast<uint64_t>(rect.GetWidth() * rect.GetHeight());
178     }
179 
180     if (displayArea > 0) {
181         g_dirtyRegionPercentage =
182             maxPercentValue * static_cast<double>(dirtyRegionArea) / static_cast<double>(displayArea);
183     }
184     if (g_dirtyRegionPercentage > maxPercentValue) {
185         g_dirtyRegionPercentage = maxPercentValue;
186     }
187 }
188 
Init(RSRenderService* renderService)189 void RSProfiler::Init(RSRenderService* renderService)
190 {
191     g_renderService = renderService;
192     g_mainThread = g_renderService ? g_renderService->mainThread_ : nullptr;
193     g_context = g_mainThread ? g_mainThread->context_.get() : nullptr;
194 
195     RSSystemProperties::WatchSystemProperty(SYS_KEY_ENABLED, OnFlagChangedCallback, nullptr);
196     RSSystemProperties::WatchSystemProperty(SYS_KEY_BETARECORDING, OnFlagChangedCallback, nullptr);
197     bool isEnabled = RSSystemProperties::GetProfilerEnabled();
198     bool isBetaRecord = RSSystemProperties::GetBetaRecordingMode() != 0;
199     HRPD("Profiler flags changed enabled=%{public}d beta_record=%{public}d", isEnabled ? 1 : 0, isBetaRecord ? 1 : 0);
200 
201     if (!IsEnabled()) {
202         return;
203     }
204 
205     OnWorkModeChanged();
206 }
207 
StartNetworkThread()208 void RSProfiler::StartNetworkThread()
209 {
210     if (Network::IsRunning()) {
211         return;
212     }
213     auto networkRunLambda = []() {
214         Network::Run();
215     };
216     std::thread thread(networkRunLambda);
217     thread.detach();
218 }
219 
OnCreateConnection(pid_t pid)220 void RSProfiler::OnCreateConnection(pid_t pid)
221 {
222     if (!IsEnabled()) {
223         return;
224     }
225 
226     if (IsRecording()) {
227         g_recordFile.AddHeaderPid(pid);
228     }
229 }
230 
OnRemoteRequest(RSIRenderServiceConnection* connection, uint32_t code, MessageParcel& parcel, MessageParcel& , MessageOption& option)231 void RSProfiler::OnRemoteRequest(RSIRenderServiceConnection* connection, uint32_t code, MessageParcel& parcel,
232     MessageParcel& /*reply*/, MessageOption& option)
233 {
234     if (!IsEnabled()) {
235         return;
236     }
237 
238     if (IsRecording() && (g_recordStartTime > 0.0)) {
239         const pid_t pid = GetConnectionPid(connection);
240         const auto& pids = g_recordFile.GetHeaderPids();
241         if (std::find(std::begin(pids), std::end(pids), pid) != std::end(pids)) {
242             const double deltaTime = Now() - g_recordStartTime;
243 
244             std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
245 
246             char headerType = 1; // parcel data
247             stream.write(reinterpret_cast<const char*>(&headerType), sizeof(headerType));
248             stream.write(reinterpret_cast<const char*>(&deltaTime), sizeof(deltaTime));
249 
250             // set sending pid
251             stream.write(reinterpret_cast<const char*>(&pid), sizeof(pid));
252             stream.write(reinterpret_cast<const char*>(&code), sizeof(code));
253 
254             const size_t dataSize = parcel.GetDataSize();
255             stream.write(reinterpret_cast<const char*>(&dataSize), sizeof(dataSize));
256             stream.write(reinterpret_cast<const char*>(parcel.GetData()), dataSize);
257 
258             const int32_t flags = option.GetFlags();
259             stream.write(reinterpret_cast<const char*>(&flags), sizeof(flags));
260             const int32_t waitTime = option.GetWaitTime();
261             stream.write(reinterpret_cast<const char*>(&waitTime), sizeof(waitTime));
262 
263             const std::string out = stream.str();
264             constexpr size_t headerOffset = 8 + 1;
265             if (out.size() >= headerOffset) {
266                 g_recordFile.WriteRSData(deltaTime, out.data() + headerOffset, out.size() - headerOffset);
267             }
268             Network::SendBinary(out.data(), out.size());
269         }
270     }
271 
272     if (IsLoadSaveFirstScreenInProgress()) {
273         // saving screen right now
274     }
275     if (IsPlaying()) {
276         SetTransactionTimeCorrection(g_playbackStartTime, g_playbackFile.GetWriteTime());
277         SetSubstitutingPid(g_playbackFile.GetHeaderPids(), g_playbackPid, g_playbackParentNodeId);
278         SetMode(Mode::READ);
279     } else if (IsRecording()) {
280         SetMode(Mode::WRITE);
281     } else {
282         SetMode(Mode::NONE);
283     }
284 }
285 
OnRecvParcel(const MessageParcel* parcel, RSTransactionData* data)286 void RSProfiler::OnRecvParcel(const MessageParcel* parcel, RSTransactionData* data)
287 {
288     if (!IsEnabled()) {
289         return;
290     }
291 
292     if (parcel && IsParcelMock(*parcel)) {
293         data->SetSendingPid(Utils::GetMockPid(data->GetSendingPid()));
294     }
295 }
296 
CreateMockConnection(pid_t pid)297 void RSProfiler::CreateMockConnection(pid_t pid)
298 {
299     if (!IsEnabled() || !g_renderService) {
300         return;
301     }
302 
303     auto tokenObj = new IRemoteStub<RSIConnectionToken>();
304 
305     sptr<RSIRenderServiceConnection> newConn(new RSRenderServiceConnection(pid, g_renderService, g_mainThread,
306         g_renderService->screenManager_, tokenObj, g_renderService->appVSyncDistributor_));
307 
308     sptr<RSIRenderServiceConnection> tmp;
309 
310     std::unique_lock<std::mutex> lock(g_renderService->mutex_);
311     // if connections_ has the same token one, replace it.
312     if (g_renderService->connections_.count(tokenObj) > 0) {
313         tmp = g_renderService->connections_.at(tokenObj);
314     }
315     g_renderService->connections_[tokenObj] = newConn;
316     lock.unlock();
317     g_mainThread->AddTransactionDataPidInfo(pid);
318 }
319 
GetConnection(pid_t pid)320 RSRenderServiceConnection* RSProfiler::GetConnection(pid_t pid)
321 {
322     if (!g_renderService) {
323         return nullptr;
324     }
325 
326     for (const auto& pair : g_renderService->connections_) {
327         auto connection = static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr());
328         if (connection->remotePid_ == pid) {
329             return connection;
330         }
331     }
332 
333     return nullptr;
334 }
335 
GetConnectionPid(RSIRenderServiceConnection* connection)336 pid_t RSProfiler::GetConnectionPid(RSIRenderServiceConnection* connection)
337 {
338     if (!g_renderService || !connection) {
339         return 0;
340     }
341 
342     for (const auto& pair : g_renderService->connections_) {
343         auto renderServiceConnection = static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr());
344         if (renderServiceConnection == connection) {
345             return renderServiceConnection->remotePid_;
346         }
347     }
348 
349     return 0;
350 }
351 
GetConnectionsPids()352 std::vector<pid_t> RSProfiler::GetConnectionsPids()
353 {
354     if (!g_renderService) {
355         return {};
356     }
357 
358     std::vector<pid_t> pids;
359     pids.reserve(g_renderService->connections_.size());
360     for (const auto& pair : g_renderService->connections_) {
361         pids.push_back(static_cast<RSRenderServiceConnection*>(pair.second.GetRefPtr())->remotePid_);
362     }
363     return pids;
364 }
365 
OnFlagChangedCallback(const char *key, const char *value, void *context)366 void RSProfiler::OnFlagChangedCallback(const char *key, const char *value, void *context)
367 {
368     constexpr int8_t two = 2;
369     if (!strcmp(key, SYS_KEY_ENABLED)) {
370         signalFlagChanged_ = two;
371         AwakeRenderServiceThread();
372     }
373     if (!strcmp(key, SYS_KEY_BETARECORDING)) {
374         signalFlagChanged_ = two;
375         AwakeRenderServiceThread();
376     }
377 }
378 
OnWorkModeChanged()379 void RSProfiler::OnWorkModeChanged()
380 {
381     if (IsEnabled()) {
382         if (IsBetaRecordEnabled()) {
383             HRPD("RSProfiler: Stop network. Start beta-recording.");
384             Network::Stop();
385             StartBetaRecord();
386         } else {
387             StopBetaRecord();
388             StartNetworkThread();
389             HRPD("RSProfiler: Stop beta-recording (if running). Start network.");
390         }
391     } else {
392         HRPD("RSProfiler: Stop recording. Stop network.");
393         StopBetaRecord();
394         RecordStop(ArgList());
395         Network::Stop();
396     }
397 }
398 
ProcessSignalFlag()399 void RSProfiler::ProcessSignalFlag()
400 {
401     if (signalFlagChanged_ <= 0) {
402         return;
403     }
404 
405     signalFlagChanged_--;
406     if (!signalFlagChanged_) {
407         bool newEnabled = RSSystemProperties::GetProfilerEnabled();
408         bool newBetaRecord = RSSystemProperties::GetBetaRecordingMode() != 0;
409         HRPD("Profiler flags changed enabled=%{public}d beta_record=%{public}d", newEnabled ? 1 : 0,
410             newBetaRecord ? 1 : 0);
411         if (enabled_ && !newEnabled) {
412             const ArgList dummy;
413             if (GetMode() == Mode::READ) {
414                 PlaybackStop(dummy);
415             }
416             if (GetMode() == Mode::WRITE) {
417                 RecordStop(dummy);
418             }
419         }
420         if (enabled_ != newEnabled || IsBetaRecordEnabled() != newBetaRecord) {
421             enabled_ = newEnabled;
422             betaRecordingEnabled_ = newBetaRecord;
423             OnWorkModeChanged();
424         }
425     }
426     AwakeRenderServiceThread();
427 }
428 
OnProcessCommand()429 void RSProfiler::OnProcessCommand()
430 {
431     ProcessSignalFlag();
432 
433     if (!IsEnabled()) {
434         return;
435     }
436 
437     if (IsPlaying()) {
438         ResetAnimationStamp();
439     }
440 }
441 
OnRenderBegin()442 void RSProfiler::OnRenderBegin()
443 {
444     if (!IsEnabled()) {
445         return;
446     }
447     HRPD("OnRenderBegin()");
448     g_renderServiceCpuId = Utils::GetCpuId();
449 }
450 
OnRenderEnd()451 void RSProfiler::OnRenderEnd()
452 {
453     if (!IsEnabled()) {
454         return;
455     }
456 
457     g_renderServiceCpuId = Utils::GetCpuId();
458 }
459 
OnParallelRenderBegin()460 void RSProfiler::OnParallelRenderBegin()
461 {
462     if (!IsEnabled()) {
463         return;
464     }
465 
466     if (g_calcPerfNode > 0) {
467         // force render thread to be on fastest CPU
468         constexpr uint32_t spamCount = 10'000;
469         std::vector<int> data;
470         data.resize(spamCount);
471         for (uint32_t i = 0; i < spamCount; i++) {
472             for (uint32_t j = i + 1; j < spamCount; j++) {
473                 std::swap(data[i], data[j]);
474             }
475         }
476 
477         constexpr uint32_t trashCashStep = 64;
478         constexpr uint32_t newCount = spamCount * trashCashStep;
479         constexpr int trashNum = 0x7F;
480         data.resize(newCount);
481         for (uint32_t i = 0; i < spamCount; i++) {
482             data[i * trashCashStep] = trashNum;
483         }
484     }
485 
486     g_frameRenderBeginTimestamp = RawNowNano();
487 }
488 
489 void RSProfiler::OnParallelRenderEnd(uint32_t frameNumber)
490 {
491     const uint64_t frameLengthNanosecs = RawNowNano() - g_frameRenderBeginTimestamp;
492     CalcNodeWeigthOnFrameEnd(frameLengthNanosecs);
493 
494     if (!IsRecording() || (g_recordStartTime <= 0.0)) {
495         return;
496     }
497 
498     const double currentTime = Utils::ToSeconds(g_frameRenderBeginTimestamp);
499     const double timeSinceRecordStart = currentTime - g_recordStartTime;
500 
501     if (timeSinceRecordStart > 0.0) {
502         RSCaptureData captureData;
503         captureData.SetTime(timeSinceRecordStart);
504         captureData.SetProperty(RSCaptureData::KEY_RENDER_FRAME_NUMBER, frameNumber);
505         captureData.SetProperty(RSCaptureData::KEY_RENDER_FRAME_LEN, frameLengthNanosecs);
506 
507         std::vector<char> out;
508         DataWriter archive(out);
509         char headerType = static_cast<char>(PackageID::RS_PROFILER_RENDER_METRICS);
510         archive.Serialize(headerType);
511         captureData.Serialize(archive);
512 
513         Network::SendBinary(out.data(), out.size());
514         g_recordFile.WriteRSMetrics(0, timeSinceRecordStart, out.data(), out.size());
515     }
516 }
517 
518 bool RSProfiler::ShouldBlockHWCNode()
519 {
520     if (!IsEnabled()) {
521         return false;
522     }
523 
524     return GetMode() == Mode::READ;
525 }
526 
527 void RSProfiler::OnFrameBegin()
528 {
529     if (!IsEnabled()) {
530         return;
531     }
532 
533     g_frameBeginTimestamp = RawNowNano();
534     g_renderServiceCpuId = Utils::GetCpuId();
535     g_frameNumber++;
536 
537     StartBetaRecord();
538 }
539 
540 void RSProfiler::ProcessPauseMessage()
541 {
542     if (!IsPlaying()) {
543         return;
544     }
545 
546     uint64_t pauseAtTime = TimePauseGet();
547     uint64_t nowTime = RawNowNano();
548     if (pauseAtTime > 0 && nowTime > pauseAtTime) {
549         const double recordPlayTime = Now() - g_playbackStartTime;
550         if (recordPlayTime > g_replayLastPauseTimeReported) {
551             int64_t vsyncId = g_playbackFile.ConvertTime2VsyncId(recordPlayTime);
552             if (vsyncId) {
553                 Respond("Replay timer paused vsyncId=" + std::to_string(vsyncId));
554             }
555             g_replayLastPauseTimeReported = recordPlayTime;
556         }
557     }
558 }
559 
560 void RSProfiler::OnFrameEnd()
561 {
562     if (!IsEnabled()) {
563         return;
564     }
565 
566     g_renderServiceCpuId = Utils::GetCpuId();
567     ProcessCommands();
568     ProcessSendingRdc();
569     RecordUpdate();
570 
571     UpdateDirtyRegionBetaRecord(g_dirtyRegionPercentage);
572     UpdateBetaRecord();
573     BlinkNodeUpdate();
574     CalcPerfNodeUpdate();
575 
576     ProcessPauseMessage();
577 
578     g_renderServiceCpuId = Utils::GetCpuId();
579 
580     std::string value;
581     constexpr int maxMsgPerFrame = 32;
582     value = SendMessageBase();
583     for (int i = 0; value != "" && i < maxMsgPerFrame; value = SendMessageBase(), i++) {
584         if (!value.length()) {
585             break;
586         }
587         Network::SendMessage(value);
588     }
589 }
590 
591 void RSProfiler::CalcNodeWeigthOnFrameEnd(uint64_t frameLength)
592 {
593     g_renderServiceRenderCpuId = Utils::GetCpuId();
594 
595     if (g_calcPerfNode == 0) {
596         return;
597     }
598 
599     g_calcPerfNodeTime[g_calcPerfNodeTry] = frameLength;
600     g_calcPerfNodeTry++;
601     if (g_calcPerfNodeTry < g_effectiveNodeTimeCount) {
602         AwakeRenderServiceThread();
603         return;
604     }
605 
606     std::sort(g_calcPerfNodeTime, g_calcPerfNodeTime + g_effectiveNodeTimeCount);
607 
608     const uint16_t startCnt = g_effectiveNodeTimeCount / 4;
609     const uint16_t endCnt = g_effectiveNodeTimeCount - startCnt;
610     uint64_t avgValue = 0;
611     for (auto i = startCnt; i < endCnt; i++) {
612         avgValue += g_calcPerfNodeTime[i];
613     }
614     avgValue /= endCnt - startCnt;
615 
616     if (g_calcPerfNodeExcludeDown) {
617         g_mapNode2UpTime[g_calcPerfNode] = avgValue;
618     } else {
619         g_mapNode2UpDownTime[g_calcPerfNode] = avgValue;
620     }
621 
622     constexpr float nanoToMs = 1000'000.0f;
623 
624     if (g_calcPerfNodeExcludeDown) {
625         Respond("CALC_PERF_NODE_RESULT: U->" + std::to_string(g_calcPerfNode) + " " + std::to_string(avgValue) +
626             " inMS=" + std::to_string(avgValue / nanoToMs) + " tries=" + std::to_string(g_effectiveNodeTimeCount));
627     } else {
628         Respond("CALC_PERF_NODE_RESULT: UD->" + std::to_string(g_calcPerfNode) + " " + std::to_string(avgValue) +
629             " inMS=" + std::to_string(avgValue / nanoToMs) + " tries=" + std::to_string(g_effectiveNodeTimeCount));
630     }
631 
632     g_calcPerfNode = 0;
633 
634     AwakeRenderServiceThread();
635     g_renderServiceCpuId = Utils::GetCpuId();
636 }
637 
638 void RSProfiler::RenderServiceTreeDump(JsonWriter& out, pid_t pid)
639 {
640     RS_TRACE_NAME("GetDumpTreeJSON");
641 
642     if (!g_context) {
643         return;
644     }
645 
646     const bool useMockPid = pid > 0 && GetMode() == Mode::READ;
647     if (useMockPid) {
648         pid = Utils::GetMockPid(pid);
649     }
650 
651     auto& animation = out["Animation Node"];
652     animation.PushArray();
653     for (auto& [nodeId, _] : g_context->animatingNodeList_) {
654         if (!pid) {
655             animation.Append(nodeId);
656         } else if (pid == Utils::ExtractPid(nodeId)) {
657             animation.Append(nodeId);
658         }
659     }
660     animation.PopArray();
661 
662     auto rootNode = g_context->GetGlobalRootRenderNode();
663     if (pid) {
664         rootNode = nullptr;
665         auto& nodeMap = RSMainThread::Instance()->GetContext().GetMutableNodeMap();
666         nodeMap.TraversalNodes([&rootNode, pid](const std::shared_ptr<RSBaseRenderNode>& node) {
667             if (node == nullptr) {
668                 return;
669             }
670             if (!node->GetSortedChildren()) {
671                 return;
672             }
673             auto parentPtr = node->GetParent().lock();
674             if (parentPtr != nullptr && !rootNode &&
675                 Utils::ExtractPid(node->GetId()) != Utils::ExtractPid(parentPtr->GetId()) &&
676                 Utils::ExtractPid(node->GetId()) == pid && node->GetSortedChildren()->size() > 0) {
677                 rootNode = node;
678                 Respond("Root node found: " + std::to_string(rootNode->GetId()));
679             }
680         });
681     }
682 
683     auto& root = out["Root node"];
684     if (rootNode) {
685         DumpNode(*rootNode, root, useMockPid, pid > 0);
686     } else {
687         Respond("rootNode not found");
688         root.PushObject();
689         root.PopObject();
690     }
691 }
692 
693 uint64_t RSProfiler::RawNowNano()
694 {
695     return Utils::Now();
696 }
697 
698 uint64_t RSProfiler::NowNano()
699 {
700     return PatchTime(RawNowNano());
701 }
702 
703 double RSProfiler::Now()
704 {
705     return Utils::ToSeconds(NowNano());
706 }
707 
708 bool RSProfiler::IsRecording()
709 {
710     return IsEnabled() && g_recordFile.IsOpen();
711 }
712 
713 bool RSProfiler::IsPlaying()
714 {
715     return IsEnabled() && g_playbackFile.IsOpen();
716 }
717 
718 void RSProfiler::ScheduleTask(std::function<void()> && task)
719 {
720     if (g_mainThread) {
721         g_mainThread->PostTask(std::move(task));
722     }
723 }
724 
725 void RSProfiler::RequestNextVSync()
726 {
727     if (g_mainThread) {
728         g_mainThread->RequestNextVSync();
729     }
730     ScheduleTask([]() { g_mainThread->RequestNextVSync(); });
731 }
732 
733 void RSProfiler::AwakeRenderServiceThread()
734 {
735     if (g_mainThread) {
736         g_mainThread->RequestNextVSync();
737         g_mainThread->SetAccessibilityConfigChanged();
738         g_mainThread->SetDirtyFlag();
739     }
740     ScheduleTask([]() {
741         g_mainThread->SetAccessibilityConfigChanged();
742         g_mainThread->SetDirtyFlag();
743         g_mainThread->RequestNextVSync();
744     });
745 }
746 
747 void RSProfiler::ResetAnimationStamp()
748 {
749     if (g_mainThread && g_context) {
750         g_mainThread->lastAnimateTimestamp_ = g_context->GetCurrentTimestamp();
751     }
752 }
753 
754 std::shared_ptr<RSRenderNode> RSProfiler::GetRenderNode(uint64_t id)
755 {
756     return g_context ? g_context->GetMutableNodeMap().GetRenderNode(id) : nullptr;
757 }
758 
759 bool RSProfiler::IsLoadSaveFirstScreenInProgress()
760 {
761     return (GetMode() == Mode::WRITE_EMUL || GetMode() == Mode::READ_EMUL);
762 }
763 
764 void RSProfiler::HiddenSpaceTurnOn()
765 {
766     if (!g_childOfDisplayNodes.empty()) {
767         HiddenSpaceTurnOff();
768     }
769 
770     const auto& rootRenderNode = g_context->GetGlobalRootRenderNode();
771     if (rootRenderNode == nullptr) {
772         RS_LOGE("RSProfiler::HiddenSpaceTurnOn rootRenderNode is nullptr");
773         return;
774     }
775     auto& children = *rootRenderNode->GetChildren();
776     if (children.empty()) {
777         return;
778     }
779     if (auto& displayNode = children.front()) {
780         if (auto rootNode = GetRenderNode(Utils::PatchNodeId(0))) {
781             g_childOfDisplayNodes = *displayNode->GetChildren();
782 
783             displayNode->ClearChildren();
784             displayNode->AddChild(rootNode);
785         }
786     }
787 
788     g_mainThread->SetDirtyFlag();
789     AwakeRenderServiceThread();
790 }
791 
792 void RSProfiler::HiddenSpaceTurnOff()
793 {
794     const auto& rootRenderNode = g_context->GetGlobalRootRenderNode();
795     if (rootRenderNode == nullptr) {
796         RS_LOGE("RSProfiler::HiddenSpaceTurnOff rootRenderNode is nullptr");
797         return;
798     }
799     const auto& children = *rootRenderNode->GetChildren();
800     if (children.empty()) {
801         return;
802     }
803     if (auto& displayNode = children.front()) {
804         displayNode->ClearChildren();
805         for (const auto& child : g_childOfDisplayNodes) {
806             displayNode->AddChild(child);
807         }
808         FilterMockNode(*g_context);
809         RSTypefaceCache::Instance().ReplayClear();
810         g_childOfDisplayNodes.clear();
811     }
812 
813     g_mainThread->SetDirtyFlag();
814 
815     AwakeRenderServiceThread();
816 }
817 
818 std::string RSProfiler::FirstFrameMarshalling(uint32_t fileVersion)
819 {
820     if (!g_context) {
821         return "";
822     }
823 
824     std::stringstream stream;
825     TypefaceMarshalling(stream, fileVersion);
826 
827     SetMode(Mode::WRITE_EMUL);
828     DisableSharedMemory();
829     MarshalNodes(*g_context, stream, fileVersion);
830     EnableSharedMemory();
831     SetMode(Mode::NONE);
832 
833     const int32_t focusPid = g_mainThread->focusAppPid_;
834     stream.write(reinterpret_cast<const char*>(&focusPid), sizeof(focusPid));
835 
836     const int32_t focusUid = g_mainThread->focusAppUid_;
837     stream.write(reinterpret_cast<const char*>(&focusUid), sizeof(focusUid));
838 
839     const uint64_t focusNodeId = g_mainThread->focusNodeId_;
840     stream.write(reinterpret_cast<const char*>(&focusNodeId), sizeof(focusNodeId));
841 
842     const std::string bundleName = g_mainThread->focusAppBundleName_;
843     size_t size = bundleName.size();
844     stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
845     stream.write(reinterpret_cast<const char*>(bundleName.data()), size);
846 
847     const std::string abilityName = g_mainThread->focusAppAbilityName_;
848     size = abilityName.size();
849     stream.write(reinterpret_cast<const char*>(&size), sizeof(size));
850     stream.write(reinterpret_cast<const char*>(abilityName.data()), size);
851 
852     return stream.str();
853 }
854 
855 void RSProfiler::FirstFrameUnmarshalling(const std::string& data, uint32_t fileVersion)
856 {
857     std::stringstream stream;
858     stream.str(data);
859 
860     TypefaceUnmarshalling(stream, fileVersion);
861 
862     SetMode(Mode::READ_EMUL);
863 
864     DisableSharedMemory();
865     UnmarshalNodes(*g_context, stream, fileVersion);
866     EnableSharedMemory();
867 
868     SetMode(Mode::NONE);
869 
870     int32_t focusPid = 0;
871     stream.read(reinterpret_cast<char*>(&focusPid), sizeof(focusPid));
872 
873     int32_t focusUid = 0;
874     stream.read(reinterpret_cast<char*>(&focusUid), sizeof(focusUid));
875 
876     uint64_t focusNodeId = 0;
877     stream.read(reinterpret_cast<char*>(&focusNodeId), sizeof(focusNodeId));
878 
879     size_t size = 0;
880     stream.read(reinterpret_cast<char*>(&size), sizeof(size));
881     std::string bundleName;
882     bundleName.resize(size, ' ');
883     stream.read(reinterpret_cast<char*>(bundleName.data()), size);
884 
885     stream.read(reinterpret_cast<char*>(&size), sizeof(size));
886     std::string abilityName;
887     abilityName.resize(size, ' ');
888     stream.read(reinterpret_cast<char*>(abilityName.data()), size);
889 
890     focusPid = Utils::GetMockPid(focusPid);
891     focusNodeId = Utils::PatchNodeId(focusNodeId);
892 
893     CreateMockConnection(focusPid);
894     g_mainThread->SetFocusAppInfo(focusPid, focusUid, bundleName, abilityName, focusNodeId);
895 }
896 
897 void RSProfiler::TypefaceMarshalling(std::stringstream& stream, uint32_t fileVersion)
898 {
899     if (fileVersion >= RSFILE_VERSION_RENDER_TYPEFACE_FIX) {
900         std::stringstream fontStream;
901         RSTypefaceCache::Instance().ReplaySerialize(fontStream);
902         size_t fontStreamSize = fontStream.str().size();
903         stream.write(reinterpret_cast<const char*>(&fontStreamSize), sizeof(fontStreamSize));
904         stream.write(reinterpret_cast<const char*>(fontStream.str().c_str()), fontStreamSize);
905     }
906 }
907 
908 void RSProfiler::TypefaceUnmarshalling(std::stringstream& stream, uint32_t fileVersion)
909 {
910     if (fileVersion >= RSFILE_VERSION_RENDER_TYPEFACE_FIX) {
911         std::vector<uint8_t> fontData;
912         std::stringstream fontStream;
913         size_t fontStreamSize;
914         stream.read(reinterpret_cast<char*>(&fontStreamSize), sizeof(fontStreamSize));
915         fontData.resize(fontStreamSize);
916         stream.read(reinterpret_cast<char*>(fontData.data()), fontStreamSize);
917         fontStream.write(reinterpret_cast<const char*>(fontData.data()), fontStreamSize);
918         RSTypefaceCache::Instance().ReplayDeserialize(fontStream);
919     }
920 }
921 
922 void RSProfiler::SaveRdc(const ArgList& args)
923 {
924     g_rdcSent = false;
925     RSSystemProperties::SetSaveRDC(true);
926     RSSystemProperties::SetInstantRecording(true);
927 
928     AwakeRenderServiceThread();
929     Respond("Recording current frame cmds (for .rdc) into : /data/default.drawing");
930 }
931 
932 void RSProfiler::SaveSkp(const ArgList& args)
933 {
934     const auto nodeId = args.Node();
935     RSCaptureRecorder::GetInstance().SetDrawingCanvasNodeId(nodeId);
936     if (nodeId == 0) {
937         RSSystemProperties::SetInstantRecording(true);
938         Respond("Recording full frame .skp");
939     } else {
940         Respond("Recording .skp for DrawingCanvasNode: id=" + std::to_string(nodeId));
941     }
942     AwakeRenderServiceThread();
943 }
944 
945 void RSProfiler::ProcessSendingRdc()
946 {
947     if (!RSSystemProperties::GetSaveRDC() || g_rdcSent) {
948         return;
949     }
950     AwakeRenderServiceThread();
951 
952     if (!RSCaptureRecorder::PullAndSendRdc()) {
953         return;
954     }
955     RSSystemProperties::SetSaveRDC(false);
956     g_rdcSent = true;
957 }
958 
959 static uint32_t GetImagesAdded()
960 {
961     const size_t count = ImageCache::Size();
962     const uint32_t added = count - g_lastCacheImageCount;
963     g_lastCacheImageCount = count;
964     return added;
965 }
966 
967 void RSProfiler::RecordUpdate()
968 {
969     if (!IsRecording() || (g_recordStartTime <= 0.0)) {
970         return;
971     }
972 
973     const uint64_t frameLengthNanosecs = RawNowNano() - g_frameBeginTimestamp;
974 
975     const double currentTime = Utils::ToSeconds(g_frameBeginTimestamp);
976     const double timeSinceRecordStart = currentTime - g_recordStartTime;
977 
978     if (timeSinceRecordStart > 0.0) {
979         RSCaptureData captureData;
980         captureData.SetTime(timeSinceRecordStart);
981         captureData.SetProperty(RSCaptureData::KEY_RS_FRAME_NUMBER, g_frameNumber);
982         captureData.SetProperty(RSCaptureData::KEY_RS_FRAME_LEN, frameLengthNanosecs);
983         captureData.SetProperty(RSCaptureData::KEY_RS_CMD_COUNT, GetCommandCount());
984         captureData.SetProperty(RSCaptureData::KEY_RS_CMD_EXECUTE_COUNT, GetCommandExecuteCount());
985         captureData.SetProperty(RSCaptureData::KEY_RS_CMD_PARCEL_LIST, GetCommandParcelList(g_recordStartTime));
986         captureData.SetProperty(RSCaptureData::KEY_RS_PIXEL_IMAGE_ADDED, GetImagesAdded());
987         captureData.SetProperty(RSCaptureData::KEY_RS_DIRTY_REGION, floor(g_dirtyRegionPercentage));
988         captureData.SetProperty(RSCaptureData::KEY_RS_CPU_ID, g_renderServiceCpuId.load());
989         uint64_t vsyncId = g_mainThread ? g_mainThread->vsyncId_ : 0;
990         captureData.SetProperty(RSCaptureData::KEY_RS_VSYNC_ID, vsyncId);
991         if (!g_recordMinVsync) {
992             g_recordMinVsync = vsyncId;
993         }
994         if (g_recordMaxVsync < vsyncId) {
995             g_recordMaxVsync = vsyncId;
996         }
997 
998         std::vector<char> out;
999         DataWriter archive(out);
1000         char headerType = static_cast<char>(PackageID::RS_PROFILER_RS_METRICS);
1001         archive.Serialize(headerType);
1002         captureData.Serialize(archive);
1003 
1004         Network::SendBinary(out.data(), out.size());
1005         g_recordFile.WriteRSMetrics(0, timeSinceRecordStart, out.data(), out.size());
1006     }
1007 
1008     WriteBetaRecordMetrics(g_recordFile, timeSinceRecordStart);
1009 }
1010 
1011 void RSProfiler::Respond(const std::string& message)
1012 {
1013     if (!message.empty()) {
1014         Network::SendMessage(message);
1015         HRPI("%s", message.data());
1016     }
1017 }
1018 
1019 void RSProfiler::SetSystemParameter(const ArgList& args)
1020 {
1021     if (!SystemParameter::Set(args.String(0), args.String(1))) {
1022         Respond("There is no such a system parameter");
1023     }
1024 }
1025 
1026 void RSProfiler::GetSystemParameter(const ArgList& args)
1027 {
1028     const auto parameter = SystemParameter::Find(args.String());
1029     Respond(parameter ? parameter->ToString() : "There is no such a system parameter");
1030 }
1031 
1032 void RSProfiler::Reset(const ArgList& args)
1033 {
1034     const ArgList dummy;
1035     RecordStop(dummy);
1036     PlaybackStop(dummy);
1037 
1038     Utils::FileDelete(RSFile::GetDefaultPath());
1039 
1040     Respond("Reset");
1041 }
1042 
1043 void RSProfiler::DumpSystemParameters(const ArgList& args)
1044 {
1045     Respond(SystemParameter::Dump());
1046 }
1047 
1048 void RSProfiler::DumpConnections(const ArgList& args)
1049 {
1050     if (!g_renderService) {
1051         return;
1052     }
1053 
1054     std::string out;
1055     for (const auto& pid : GetConnectionsPids()) {
1056         out += "pid=" + std::to_string(pid);
1057 
1058         const std::string path = "/proc/" + std::to_string(pid) + "/cmdline";
1059         FILE* file = Utils::FileOpen(path, "r");
1060         if (const size_t size = Utils::FileSize(file)) {
1061             std::string content;
1062             content.resize(size);
1063             Utils::FileRead(file, content.data(), content.size());
1064             Utils::FileClose(file);
1065             out += " ";
1066             out += content;
1067         }
1068         if (Utils::IsFileValid(file)) {
1069             Utils::FileClose(file);
1070         }
1071         out += "\n";
1072     }
1073     Respond(out);
1074 }
1075 
1076 void RSProfiler::DumpNodeModifiers(const ArgList& args)
1077 {
1078     if (const auto node = GetRenderNode(args.Node())) {
1079         Respond("Modifiers=" + DumpModifiers(*node));
1080     }
1081 }
1082 
1083 void RSProfiler::DumpNodeProperties(const ArgList& args)
1084 {
1085     if (const auto node = GetRenderNode(args.Node())) {
1086         Respond("RenderProperties=" + DumpRenderProperties(*node));
1087     }
1088 }
1089 
1090 void RSProfiler::DumpDrawingCanvasNodes(const ArgList& args)
1091 {
1092     if (!g_context) {
1093         return;
1094     }
1095     const auto& map = const_cast<RSContext&>(*g_context).GetMutableNodeMap();
1096     for (const auto& item : map.renderNodeMap_) {
1097         if (item.second->GetType() == RSRenderNodeType::CANVAS_DRAWING_NODE) {
1098             Respond("CANVAS_DRAWING_NODE: " + std::to_string(item.second->GetId()));
1099         }
1100     }
1101 }
1102 
1103 void RSProfiler::DrawingCanvasRedrawEnable(const ArgList& args)
1104 {
1105     const auto enable = args.Uint64(); // 0 - disabled, >0 - enabled
1106     RSProfiler::SetDrawingCanvasNodeRedraw(enable > 0);
1107 }
1108 
1109 void RSProfiler::DumpTree(const ArgList& args)
1110 {
1111     if (!g_context) {
1112         return;
1113     }
1114 
1115     std::map<std::string, std::tuple<NodeId, std::string>> list;
1116     GetSurfacesTrees(*g_context, list);
1117 
1118     std::string out = "Tree: count=" + std::to_string(static_cast<int>(GetRenderNodeCount(*g_context))) +
1119                       " time=" + std::to_string(Now()) + "\n";
1120 
1121     const std::string& node = args.String();
1122     for (const auto& item : list) {
1123         if (std::strstr(item.first.data(), node.data())) {
1124             out += "*** " + item.first + " pid=" + std::to_string(ExtractPid(std::get<0>(item.second))) +
1125                    " lowId=" + std::to_string(Utils::ExtractNodeId(std::get<0>(item.second))) + "\n" +
1126                    std::get<1>(item.second) + "\n";
1127         }
1128     }
1129 
1130     Respond(out);
1131 }
1132 
1133 void RSProfiler::DumpTreeToJson(const ArgList& args)
1134 {
1135     if (!g_context || !g_mainThread) {
1136         return;
1137     }
1138 
1139     JsonWriter json;
1140     json.PushObject();
1141     pid_t pid = args.Pid();
1142     RenderServiceTreeDump(json, pid);
1143 
1144     auto& display = json["Display"];
1145     auto displayNode = GetDisplayNode(*g_context);
1146     auto dirtyManager = displayNode ? displayNode->GetDirtyManager() : nullptr;
1147     if (dirtyManager) {
1148         const auto displayRect = dirtyManager->GetSurfaceRect();
1149         display = { displayRect.GetLeft(), displayRect.GetTop(), displayRect.GetRight(), displayRect.GetBottom() };
1150     } else {
1151         display = { 0.0f, 0.0f, 0.0f, 0.0f };
1152     }
1153 
1154     json["transactionFlags"] = g_mainThread->transactionFlags_;
1155     json["timestamp"] = g_mainThread->timestamp_;
1156     json["vsyncID"] = g_mainThread->vsyncId_;
1157 
1158     json.PopObject();
1159     Network::SendRSTreeDumpJSON(json.GetDumpString());
1160 
1161     Respond(json.GetDumpString());
1162 }
1163 
1164 void RSProfiler::ClearFilter(const ArgList& args)
1165 {
1166     const auto node = GetRenderNode(args.Node());
1167     if (!node) {
1168         Respond("error: node not found");
1169         return;
1170     }
1171 
1172     node->GetMutableRenderProperties().backgroundFilter_ = nullptr;
1173     Respond("OK");
1174     AwakeRenderServiceThread();
1175 }
1176 
1177 void RSProfiler::DumpSurfaces(const ArgList& args)
1178 {
1179     if (!g_context) {
1180         return;
1181     }
1182 
1183     std::map<NodeId, std::string> surfaces;
1184     GetSurfacesTrees(*g_context, args.Pid(), surfaces);
1185 
1186     std::string out;
1187     for (const auto& item : surfaces) {
1188         out += "*** " + std::to_string(item.first) + " pid=" + std::to_string(ExtractPid(item.first)) +
1189                " lowId=" + std::to_string(Utils::ExtractNodeId(item.first)) + "\n" + item.second + "\n";
1190     }
1191 
1192     out += "TREE: count=" + std::to_string(static_cast<int32_t>(GetRenderNodeCount(*g_context))) +
1193            " time=" + std::to_string(Now()) + "\n";
1194 
1195     Respond(out);
1196 }
1197 
1198 void RSProfiler::DumpNodeSurface(const ArgList& args)
1199 {
1200     if (g_renderService) {
1201         std::string out;
1202         g_renderService->DumpSurfaceNode(out, Utils::GetRootNodeId(args.Node()));
1203         Respond(out);
1204     }
1205 }
1206 
1207 void RSProfiler::PatchNode(const ArgList& args)
1208 {
1209     const auto node = GetRenderNode(args.Node());
1210     if (!node) {
1211         return;
1212     }
1213 
1214     const Vector4f screenRect = GetScreenRect(*g_context);
1215 
1216     auto surfaceNode = static_cast<RSSurfaceRenderNode*>(node.get());
1217     {
1218         auto& region = const_cast<Occlusion::Region&>(surfaceNode->GetVisibleRegion());
1219         region = Occlusion::Region({ screenRect[0], screenRect[1], screenRect[2], screenRect[3] }); // NOLINT
1220     }
1221 
1222     RSProperties& properties = node->GetMutableRenderProperties();
1223     properties.SetBounds(screenRect);
1224     properties.SetFrame(screenRect);
1225     properties.SetDrawRegion(std::make_shared<RectF>(screenRect));
1226 
1227     AwakeRenderServiceThread();
1228 }
1229 
1230 void RSProfiler::KillNode(const ArgList& args)
1231 {
1232     if (const auto node = GetRenderNode(args.Node())) {
1233         node->RemoveFromTree(false);
1234         AwakeRenderServiceThread();
1235         Respond("OK");
1236     }
1237 }
1238 
1239 void RSProfiler::BlinkNode(const ArgList& args)
1240 {
1241     if (const auto node = GetRenderNode(args.Node())) {
1242         const auto parent = node->GetParent().lock();
1243         auto parentChildren = parent ? parent->GetChildren() : nullptr;
1244         if (!parentChildren) {
1245             return;
1246         }
1247 
1248         g_blinkNodeId = args.Node();
1249         g_blinkNodeCount = 0;
1250 
1251         g_blinkSavedParentChildren.clear();
1252         g_blinkSavedParentChildren.push_back(parent);
1253 
1254         for (const auto& child : *parentChildren) {
1255             if (child != nullptr) {
1256                 g_blinkSavedParentChildren.push_back(child);
1257             }
1258         }
1259 
1260         AwakeRenderServiceThread();
1261         Respond("OK");
1262     }
1263 }
1264 
1265 void RSProfiler::AttachChild(const ArgList& args)
1266 {
1267     auto child = GetRenderNode(args.Uint64(0));
1268     auto parent = GetRenderNode(args.Uint64(1));
1269     if (parent && child) {
1270         parent->AddChild(child);
1271         AwakeRenderServiceThread();
1272         Respond("OK");
1273     }
1274 }
1275 
1276 void RSProfiler::KillPid(const ArgList& args)
1277 {
1278     const pid_t pid = args.Pid();
1279     if (const auto node = GetRenderNode(Utils::GetRootNodeId(static_cast<uint64_t>(pid)))) {
1280         const auto parent = node->GetParent().lock();
1281         const std::string out =
1282             "parentPid=" + std::to_string(GetPid(parent)) + " parentNode=" + std::to_string(GetNodeId(parent));
1283 
1284         g_context->GetMutableNodeMap().FilterNodeByPid(pid);
1285         AwakeRenderServiceThread();
1286         Respond(out);
1287     }
1288 }
1289 
1290 void RSProfiler::GetRoot(const ArgList& args)
1291 {
1292     if (!g_context) {
1293         return;
1294     }
1295 
1296     std::string out;
1297 
1298     const RSRenderNodeMap& map = g_context->GetMutableNodeMap();
1299     std::shared_ptr<RSRenderNode> node = map.GetRenderNode<RSRenderNode>(GetRandomSurfaceNode(*g_context));
1300     while (node && (node->GetId() != 0)) {
1301         std::string type;
1302         const RSRenderNodeType nodeType = node->GetType();
1303         if (nodeType == RSRenderNodeType::UNKNOW) {
1304             type = "UNKNOWN";
1305         } else if (nodeType == RSRenderNodeType::RS_NODE) {
1306             type = "NONE";
1307         } else if (nodeType == RSRenderNodeType::DISPLAY_NODE) {
1308             type = "DISPLAY_NODE";
1309         } else if (nodeType == RSRenderNodeType::EFFECT_NODE) {
1310             type = "EFFECT_NODE";
1311         } else if (nodeType == RSRenderNodeType::ROOT_NODE) {
1312             type = "ROOT_NODE";
1313         } else if (nodeType == RSRenderNodeType::CANVAS_DRAWING_NODE) {
1314             type = "CANVAS_DRAWING_NODE";
1315         }
1316 
1317         if (!type.empty()) {
1318             out += "pid=" + std::to_string(GetPid(node)) + " node_id=" + std::to_string(GetNodeId(node)) + "|" + type +
1319                    ";\n";
1320         }
1321 
1322         node = node->GetParent().lock();
1323     };
1324 
1325     if (node) {
1326         out += "ROOT_ID=" + std::to_string(node->GetId()); // DISPLAY_NODE;ohos.sceneboard
1327     }
1328 
1329     Respond(out);
1330 }
1331 
1332 void RSProfiler::GetDeviceInfo(const ArgList& args)
1333 {
1334     Respond(RSTelemetry::GetDeviceInfoString());
1335 }
1336 
1337 void RSProfiler::GetDeviceFrequency(const ArgList& args)
1338 {
1339     Respond(RSTelemetry::GetDeviceFrequencyString());
1340     Respond(RSTelemetry::GetCpuAffinityString());
1341 }
1342 
1343 void RSProfiler::FixDeviceEnv(const ArgList& args)
1344 {
1345     constexpr int32_t cpu = 8;
1346     Utils::SetCpuAffinity(cpu);
1347     Respond("OK");
1348 }
1349 
1350 void RSProfiler::GetPerfTree(const ArgList& args)
1351 {
1352     if (!g_context) {
1353         return;
1354     }
1355 
1356     g_nodeListPerf.clear();
1357     g_mapNode2Count.clear();
1358 
1359     auto rootNode = GetRenderNode(Utils::PatchNodeId(0));
1360     if (!rootNode) {
1361         Respond("ERROR");
1362         return;
1363     }
1364 
1365     PerfTreeFlatten(rootNode, g_nodeListPerf, g_mapNode2Count, 0);
1366 
1367     std::string outString;
1368     auto& nodeMap = g_context->GetMutableNodeMap();
1369     for (auto it = g_nodeListPerf.begin(); it != g_nodeListPerf.end(); it++) {
1370         auto node = nodeMap.GetRenderNode(it->first);
1371         if (!node) {
1372             continue;
1373         }
1374         std::string sNodeType;
1375         RSRenderNode::DumpNodeType(node->GetType(), sNodeType);
1376         outString += (it != g_nodeListPerf.begin() ? ", " : "") + std::to_string(it->first) + ":" +
1377                      std::to_string(g_mapNode2Count[it->first]) + " [" + sNodeType + "]";
1378     }
1379 
1380     std::unordered_set<uint64_t> perfNodesSet;
1381     for (const auto& item : g_nodeListPerf) {
1382         perfNodesSet.insert(item.first);
1383     }
1384 
1385     Network::SendRSTreePerfNodeList(perfNodesSet);
1386     Respond("OK: Count=" + std::to_string(g_nodeListPerf.size()) + " LIST=[" + outString + "]");
1387 }
1388 
1389 void RSProfiler::CalcPerfNodePrepareLo(const std::shared_ptr<RSRenderNode>& node, bool forceExcludeNode)
1390 {
1391         if (!node || node->id_ == Utils::PatchNodeId(0)) {
1392         return;
1393     }
1394 
1395     const auto parent = node->GetParent().lock();
1396     auto parentChildren = parent ? parent->GetChildren() : nullptr;
1397     if (!parentChildren) {
1398         return;
1399     }
1400 
1401     std::vector<std::shared_ptr<RSRenderNode>> childList;
1402     for (const auto& child : *parentChildren) {
1403         if (child != nullptr) {
1404             childList.push_back(child);
1405         }
1406     }
1407 
1408     if (forceExcludeNode) {
1409         g_calcPerfSavedChildren.emplace_back(parent, childList);
1410         parent->RemoveChild(node);
1411         node->ResetParent();
1412     } else {
1413         g_calcPerfSavedChildren.clear();
1414     }
1415 }
1416 
1417 void RSProfiler::CalcPerfNodePrepare(NodeId nodeId, uint32_t timeCount, bool excludeDown)
1418 {
1419     g_calcPerfNode = nodeId;
1420     g_effectiveNodeTimeCount = timeCount;
1421     g_calcPerfNodeExcludeDown = excludeDown;
1422     g_calcPerfSavedChildren.clear();
1423 
1424     auto node = GetRenderNode(g_calcPerfNode);
1425     CalcPerfNodePrepareLo(node, excludeDown);
1426 }
1427 
1428 static void DumpParameter(std::string& out, int& usual, const std::string& name, bool value)
1429 {
1430     out += " " + name + "=" + (value ? "true" : "false");
1431     usual += value ? 0 : 1;
1432 }
1433 
1434 void RSProfiler::PrintNodeCacheLo(const std::shared_ptr<RSRenderNode>& node)
1435 {
1436     std::string nodeStr = std::to_string(node->id_) + ": ";
1437     int usual = 0;
1438 
1439     const std::string cacheTypes[] = { "CacheType::NONE", "CacheType::DISABLED_CACHE", "CacheType::CONTENT" };
1440     const auto cacheType = static_cast<int>(node->GetCacheType());
1441     nodeStr += "CacheType=" +
1442                (cacheType > static_cast<int>(CacheType::CONTENT) ? std::to_string(cacheType) : cacheTypes[cacheType]);
1443     usual += cacheType == static_cast<int>(CacheType::NONE) ? 1 : 0;
1444 
1445     const std::string drawingCacheTypes[] = { "RSDrawingCacheType::DISABLED_CACHE", "RSDrawingCacheType::FORCED_CACHE",
1446         "RSDrawingCacheType::TARGETED_CACHE", "RSDrawingCacheType::FOREGROUND_FILTER_CACHE" };
1447     const int drawingCacheType = node->GetDrawingCacheType();
1448     nodeStr += "DrawingCacheType=" + (drawingCacheType > RSDrawingCacheType::FOREGROUND_FILTER_CACHE
1449                                              ? std::to_string(drawingCacheType)
1450                                              : drawingCacheTypes[drawingCacheType]);
1451     usual += (cacheType == RSDrawingCacheType::DISABLED_CACHE) ? 1 : 0;
1452 
1453     DumpParameter(nodeStr, usual, "HasCachedTexture", node->HasCachedTexture());
1454     DumpParameter(nodeStr, usual, "DrawInGroup", node->IsSuggestedDrawInGroup());
1455     DumpParameter(nodeStr, usual, "CacheSurfaceValid", node->IsCacheSurfaceValid());
1456     DumpParameter(nodeStr, usual, "CacheCompletedSurfaceValid", node->IsCacheCompletedSurfaceValid());
1457     if (constexpr int usualParamCnt = 6; usual >= usualParamCnt) {
1458         return;
1459     }
1460     Respond(nodeStr);
1461 }
1462 
1463 void RSProfiler::PrintNodeCache(const ArgList& args)
1464 {
1465     NodeId nodeId = args.Uint64();
1466     auto node = GetRenderNode(nodeId);
1467     if (node == nullptr) {
1468         Respond("node not found");
1469         return;
1470     }
1471     PrintNodeCacheLo(node);
1472 }
1473 
1474 void RSProfiler::PrintNodeCacheAll(const ArgList& args)
1475 {
1476     auto& nodeMap = RSMainThread::Instance()->GetContext().GetMutableNodeMap();
1477     nodeMap.TraversalNodes([](const std::shared_ptr<RSBaseRenderNode>& node) {
1478         if (node == nullptr) {
1479             return;
1480         }
1481         PrintNodeCacheLo(node);
1482     });
1483 }
1484 
1485 void RSProfiler::CalcPerfNode(const ArgList& args)
1486 {
1487     NodeId nodeId = args.Uint64();
1488     uint32_t timeCount = args.Uint32(1);
1489     const bool excludeDown = args.Uint32(2) > 0;
1490 
1491     if (timeCount < CALC_PERF_NODE_TIME_COUNT_MIN) {
1492         timeCount = CALC_PERF_NODE_TIME_COUNT_MAX;
1493     }
1494     if (timeCount > CALC_PERF_NODE_TIME_COUNT_MAX) {
1495         timeCount = CALC_PERF_NODE_TIME_COUNT_MAX;
1496     }
1497 
1498     Respond("CalcPerfNode: calculating...");
1499 
1500     g_nodeListPerf.clear();
1501     g_nodeListPerf.emplace_back(nodeId, 0);
1502     g_mapNode2UpTime.clear();
1503     g_mapNode2UpDownTime.clear();
1504     g_nodeListPerfCalcIndex = 0;
1505     g_effectiveNodeTimeCount = timeCount;
1506     CalcPerfNodeAllStep();
1507     AwakeRenderServiceThread();
1508 }
1509 
1510 void RSProfiler::SocketShutdown(const ArgList& args)
1511 {
1512     Network::ForceShutdown();
1513 }
1514 
1515 void RSProfiler::Version(const ArgList& args)
1516 {
1517     Respond("Version: " + std::to_string(RSFILE_VERSION_LATEST));
1518 }
1519 
1520 void RSProfiler::FileVersion(const ArgList& args)
1521 {
1522     Respond("File version: " + std::to_string(RSFILE_VERSION_LATEST));
1523 }
1524 
1525 void RSProfiler::CalcPerfNodeAll(const ArgList& args)
1526 {
1527     if (g_nodeListPerf.empty()) {
1528         Respond("ERROR");
1529         return;
1530     }
1531 
1532     g_mapNode2UpTime.clear();
1533     g_mapNode2UpDownTime.clear();
1534     g_nodeListPerfCalcIndex = 0;
1535     g_effectiveNodeTimeCount = CALC_PERF_NODE_TIME_COUNT_MIN;
1536     CalcPerfNodeAllStep();
1537     AwakeRenderServiceThread();
1538 }
1539 
1540 void RSProfiler::CalcPerfNodeAllStep()
1541 {
1542     if (g_nodeListPerfCalcIndex < 0) {
1543         return;
1544     }
1545 
1546     const auto doublePerfListSize = static_cast<int32_t>(g_nodeListPerf.size()) * 2;
1547     if (g_nodeListPerfCalcIndex >= doublePerfListSize) {
1548         g_nodeListPerfCalcIndex = -1;
1549 
1550         for (auto it : g_nodeListPerf) {
1551             const auto node = GetRenderNode(it.first);
1552             const auto parent = node ? node->GetParent().lock() : nullptr;
1553             if (!parent || !g_mapNode2UpTime.count(node->id_) || !g_mapNode2UpDownTime.count(node->id_)) {
1554                 Respond("CALC_RESULT [" + std::to_string(node->id_) + "] error");
1555                 Network::SendRSTreeSingleNodePerf(node->id_, 0);
1556                 continue;
1557             }
1558 
1559             int64_t ns = (int64_t)g_mapNode2UpDownTime[node->id_] - (int64_t)g_mapNode2UpTime[node->id_];
1560             constexpr float nsToMs = 1000.0f;
1561             double ms = static_cast<double>(ns) / nsToMs;
1562             ms /= nsToMs;
1563 
1564             Respond("CALC_RESULT [" + std::to_string(node->id_) + "] time=" + std::to_string(ms));
1565             Network::SendRSTreeSingleNodePerf(node->id_, ms);
1566         }
1567 
1568         return;
1569     }
1570 
1571     const NodeId nodeId = g_nodeListPerf[g_nodeListPerfCalcIndex / 2].first;
1572     const bool excludeDown = g_nodeListPerfCalcIndex % 2;
1573     CalcPerfNodePrepare(nodeId, g_effectiveNodeTimeCount, excludeDown);
1574     AwakeRenderServiceThread();
1575 }
1576 
1577 void RSProfiler::TestSaveFrame(const ArgList& args)
1578 {
1579     g_testDataFrame = FirstFrameMarshalling(RSFILE_VERSION_LATEST);
1580     Respond("Save Frame Size: " + std::to_string(g_testDataFrame.size()));
1581 }
1582 
1583 void RSProfiler::TestLoadFrame(const ArgList& args)
1584 {
1585     FirstFrameUnmarshalling(g_testDataFrame, RSFILE_VERSION_LATEST);
1586     Respond("Load Frame Size: " + std::to_string(g_testDataFrame.size()));
1587 }
1588 
1589 void RSProfiler::TestSwitch(const ArgList& args)
1590 {
1591     if (g_childOfDisplayNodes.empty()) {
1592         HiddenSpaceTurnOn();
1593         Respond("OK: HiddenSpaceTurnOn");
1594     } else {
1595         HiddenSpaceTurnOff();
1596         Respond("OK: HiddenSpaceTurnOff");
1597     }
1598 }
1599 
1600 void RSProfiler::RecordStart(const ArgList& args)
1601 {
1602     g_recordStartTime = 0.0;
1603 
1604     ImageCache::Reset();
1605     g_lastCacheImageCount = 0;
1606 
1607     if (!OpenBetaRecordFile(g_recordFile)) {
1608         g_recordFile.SetVersion(RSFILE_VERSION_LATEST);
1609         g_recordFile.Create(RSFile::GetDefaultPath());
1610     }
1611 
1612     g_recordMinVsync = 0;
1613     g_recordMaxVsync = 0;
1614 
1615     g_recordFile.AddLayer(); // add 0 layer
1616 
1617     FilterMockNode(*g_context);
1618     RSTypefaceCache::Instance().ReplayClear();
1619 
1620     g_recordFile.AddHeaderFirstFrame(FirstFrameMarshalling(g_recordFile.GetVersion()));
1621 
1622     const std::vector<pid_t> pids = GetConnectionsPids();
1623     for (pid_t pid : pids) {
1624         g_recordFile.AddHeaderPid(pid);
1625     }
1626 
1627     SetMode(Mode::WRITE);
1628 
1629     g_recordStartTime = Now();
1630     g_frameNumber = 0;
1631 
1632     if (IsBetaRecordStarted()) {
1633         return;
1634     }
1635 
1636     std::thread thread([]() {
1637         while (IsRecording()) {
1638             if (g_recordStartTime >= 0) {
1639                 SendTelemetry(Now() - g_recordStartTime);
1640             }
1641             static constexpr int32_t GFX_METRICS_SEND_INTERVAL = 8;
1642             std::this_thread::sleep_for(std::chrono::milliseconds(GFX_METRICS_SEND_INTERVAL));
1643         }
1644     });
1645     thread.detach();
1646 
1647     Respond("Network: Record start");
1648 }
1649 
1650 void RSProfiler::RecordStop(const ArgList& args)
1651 {
1652     if (!IsRecording()) {
1653         return;
1654     }
1655 
1656     g_recordFile.SetWriteTime(g_recordStartTime);
1657 
1658     std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
1659 
1660     if (!IsBetaRecordStarted()) {
1661         // DOUBLE WORK - send header of file
1662         const char headerType = 0;
1663         stream.write(reinterpret_cast<const char*>(&headerType), sizeof(headerType));
1664         stream.write(reinterpret_cast<const char*>(&g_recordStartTime), sizeof(g_recordStartTime));
1665 
1666         const uint32_t pidCount = g_recordFile.GetHeaderPids().size();
1667         stream.write(reinterpret_cast<const char*>(&pidCount), sizeof(pidCount));
1668         for (auto item : g_recordFile.GetHeaderPids()) {
1669             stream.write(reinterpret_cast<const char*>(&item), sizeof(item));
1670         }
1671 
1672         // FIRST FRAME HEADER
1673         uint32_t sizeFirstFrame = static_cast<uint32_t>(g_recordFile.GetHeaderFirstFrame().size());
1674         stream.write(reinterpret_cast<const char*>(&sizeFirstFrame), sizeof(sizeFirstFrame));
1675         stream.write(reinterpret_cast<const char*>(&g_recordFile.GetHeaderFirstFrame()[0]), sizeFirstFrame);
1676 
1677         // ANIME START TIMES
1678         std::vector<std::pair<uint64_t, int64_t>> headerAnimeStartTimes;
1679         std::unordered_map<AnimationId, std::vector<int64_t>> &headerAnimeStartTimesMap = AnimeGetStartTimes();
1680         for (const auto& item : headerAnimeStartTimesMap) {
1681             for (const auto time : item.second) {
1682                 headerAnimeStartTimes.push_back({
1683                     Utils::PatchNodeId(item.first),
1684                     time - Utils::ToNanoseconds(g_recordStartTime)
1685                 });
1686             }
1687         }
1688 
1689         uint32_t startTimesSize = headerAnimeStartTimes.size();
1690         stream.write(reinterpret_cast<const char*>(&startTimesSize), sizeof(startTimesSize));
1691         stream.write(reinterpret_cast<const char*>(headerAnimeStartTimes.data()),
1692             startTimesSize * sizeof(std::pair<uint64_t, int64_t>));
1693 
1694         ImageCache::Serialize(stream);
1695         Network::SendBinary(stream.str().data(), stream.str().size());
1696     }
1697     SaveBetaRecordFile(g_recordFile);
1698     g_recordFile.Close();
1699     g_recordStartTime = 0.0;
1700 
1701     ImageCache::Reset();
1702     g_lastCacheImageCount = 0;
1703 
1704     Respond("Network: Record stop (" + std::to_string(stream.str().size()) + ")");
1705     Respond("Network: record_vsync_range " + std::to_string(g_recordMinVsync) + " " + std::to_string(g_recordMaxVsync));
1706 }
1707 
1708 void RSProfiler::PlaybackPrepareFirstFrame(const ArgList& args)
1709 {
1710     g_playbackPid = args.Pid();
1711     g_playbackStartTime = 0.0;
1712     g_playbackPauseTime = args.Fp64(1);
1713     constexpr int pathArgPos = 2;
1714     std::string path = args.String(pathArgPos);
1715     if (!Utils::FileExists(path)) {
1716         Respond("Can't playback non existing file '" + path + "'");
1717         path = RSFile::GetDefaultPath();
1718     }
1719 
1720     ImageCache::Reset();
1721 
1722     auto &animeMap = RSProfiler::AnimeGetStartTimes();
1723     animeMap.clear();
1724 
1725     Respond("Opening file " + path);
1726     g_playbackFile.Open(path);
1727     if (!g_playbackFile.IsOpen()) {
1728         Respond("Can't open file.");
1729         return;
1730     }
1731 
1732     if (args.String(0) == "VSYNC") {
1733         g_playbackFile.CacheVsyncId2Time(0);
1734         g_playbackPauseTime = g_playbackFile.ConvertVsyncId2Time(args.Int64(1));
1735     }
1736 
1737     const auto& fileAnimeStartTimes = g_playbackFile.GetAnimeStartTimes();
1738     for (const auto& item : fileAnimeStartTimes) {
1739         if (animeMap.count(item.first)) {
1740             animeMap[Utils::PatchNodeId(item.first)].push_back(item.second);
1741         } else {
1742             std::vector<int64_t> list;
1743             list.push_back(item.second);
1744             animeMap.insert({ Utils::PatchNodeId(item.first), list });
1745         }
1746     }
1747 
1748     std::string dataFirstFrame = g_playbackFile.GetHeaderFirstFrame();
1749 
1750     // get first frame data
1751     FirstFrameUnmarshalling(dataFirstFrame, g_playbackFile.GetVersion());
1752     // The number of frames loaded before command processing
1753     constexpr int defaultWaitFrames = 5;
1754     g_playbackWaitFrames = defaultWaitFrames;
1755     Respond("awake_frame(1) " + std::to_string(g_playbackWaitFrames));
1756     AwakeRenderServiceThread();
1757 }
1758 
1759 void RSProfiler::RecordSendBinary(const ArgList& args)
1760 {
1761     bool flag = args.Int8(0);
1762     Network::SetBlockBinary(!flag);
1763     if (flag) {
1764         Respond("Result: data will be sent to client during recording");
1765     } else {
1766         Respond("Result: data will NOT be sent to client during recording");
1767     }
1768 }
1769 
1770 void RSProfiler::PlaybackStart(const ArgList& args)
1771 {
1772     HiddenSpaceTurnOn();
1773 
1774     for (size_t pid : g_playbackFile.GetHeaderPids()) {
1775         CreateMockConnection(Utils::GetMockPid(pid));
1776     }
1777 
1778     g_playbackStartTime = Now();
1779 
1780     const double pauseTime = g_playbackPauseTime;
1781     if (pauseTime > 0.0) {
1782         const uint64_t currentTime = RawNowNano();
1783         const uint64_t pauseTimeStart = currentTime + Utils::ToNanoseconds(pauseTime);
1784         TimePauseAt(currentTime, pauseTimeStart);
1785     }
1786 
1787     AwakeRenderServiceThread();
1788 
1789     g_playbackShouldBeTerminated = false;
1790     g_replayLastPauseTimeReported = 0;
1791 
1792     const auto timeoutLimit = args.Int64();
1793     std::thread thread([timeoutLimit]() {
1794         while (IsPlaying()) {
1795             const int64_t timestamp = static_cast<int64_t>(RawNowNano());
1796 
1797             const double deltaTime = Now() - g_playbackStartTime;
1798             const double readTime = PlaybackUpdate(deltaTime);
1799 
1800             const int64_t timeout = timeoutLimit - static_cast<int64_t>(RawNowNano()) + timestamp;
1801             if (timeout > 0) {
1802                 std::this_thread::sleep_for(std::chrono::nanoseconds(timeout));
1803             }
1804         }
1805     });
1806     thread.detach();
1807 
1808     Respond("Playback start");
1809 }
1810 
1811 void RSProfiler::PlaybackStop(const ArgList& args)
1812 {
1813     if (g_childOfDisplayNodes.empty()) {
1814         return;
1815     }
1816     HiddenSpaceTurnOff();
1817     FilterMockNode(*g_context);
1818     constexpr int maxCountForSecurity = 1000;
1819     for (int i = 0; !RSRenderNodeGC::Instance().IsBucketQueueEmpty() && i < maxCountForSecurity; i++) {
1820         RSRenderNodeGC::Instance().ReleaseNodeBucket();
1821     }
1822     RSTypefaceCache::Instance().ReplayClear();
1823     ImageCache::Reset();
1824     g_playbackShouldBeTerminated = true;
1825     g_replayLastPauseTimeReported = 0;
1826 
1827     Respond("Playback stop");
1828 }
1829 
1830 double RSProfiler::PlaybackUpdate(double deltaTime)
1831 {
1832     std::vector<uint8_t> data;
1833     double readTime = 0.0;
1834     if (!g_playbackShouldBeTerminated && g_playbackFile.ReadRSData(deltaTime, data, readTime)) {
1835         std::stringstream stream(std::ios::in | std::ios::out | std::ios::binary);
1836         stream.write(reinterpret_cast<const char*>(data.data()), data.size());
1837         stream.seekg(0);
1838 
1839         pid_t pid = 0;
1840         stream.read(reinterpret_cast<char*>(&pid), sizeof(pid));
1841 
1842         RSRenderServiceConnection* connection = GetConnection(Utils::GetMockPid(pid));
1843         if (!connection) {
1844             const std::vector<pid_t>& pids = g_playbackFile.GetHeaderPids();
1845             if (!pids.empty()) {
1846                 connection = GetConnection(Utils::GetMockPid(pids[0]));
1847             }
1848         }
1849 
1850         if (connection) {
1851             uint32_t code = 0;
1852             stream.read(reinterpret_cast<char*>(&code), sizeof(code));
1853 
1854             size_t dataSize = 0;
1855             stream.read(reinterpret_cast<char*>(&dataSize), sizeof(dataSize));
1856 
1857             auto* data = new uint8_t[dataSize];
1858             stream.read(reinterpret_cast<char*>(data), dataSize);
1859 
1860             int32_t flags = 0;
1861             stream.read(reinterpret_cast<char*>(&flags), sizeof(flags));
1862 
1863             int32_t waitTime = 0;
1864             stream.read(reinterpret_cast<char*>(&waitTime), sizeof(waitTime));
1865 
1866             AlignedMessageParcel parcel;
1867             parcel.parcel.SetMaxCapacity(dataSize + 1);
1868             parcel.parcel.WriteBuffer(data, dataSize);
1869 
1870             delete[] data;
1871 
1872             MessageOption option;
1873             option.SetFlags(flags);
1874             option.SetWaitTime(waitTime);
1875 
1876             MessageParcel reply;
1877             connection->OnRemoteRequest(code, parcel.parcel, reply, option);
1878         }
1879     }
1880 
1881     if (g_playbackShouldBeTerminated || g_playbackFile.RSDataEOF()) {
1882         if (auto vsyncId = g_playbackFile.ConvertTime2VsyncId(deltaTime)) {
1883             Respond("Replay timer paused vsyncId=" + std::to_string(vsyncId));
1884         }
1885         g_playbackStartTime = 0.0;
1886         g_playbackFile.Close();
1887         g_playbackPid = 0;
1888         TimePauseClear();
1889         g_playbackShouldBeTerminated = false;
1890     }
1891     return readTime;
1892 }
1893 
1894 void RSProfiler::PlaybackPrepare(const ArgList& args)
1895 {
1896     const pid_t pid = args.Pid();
1897     if (!g_context || (pid == 0)) {
1898         return;
1899     }
1900 
1901     AwakeRenderServiceThread();
1902     Respond("OK");
1903 }
1904 
1905 void RSProfiler::PlaybackPause(const ArgList& args)
1906 {
1907     if (!IsPlaying()) {
1908         return;
1909     }
1910 
1911     const uint64_t currentTime = RawNowNano();
1912     const double recordPlayTime = Utils::ToSeconds(PatchTime(currentTime)) - g_playbackStartTime;
1913     TimePauseAt(g_frameBeginTimestamp, currentTime);
1914     Respond("OK: " + std::to_string(recordPlayTime));
1915 
1916     int64_t vsyncId = g_playbackFile.ConvertTime2VsyncId(recordPlayTime);
1917     if (vsyncId) {
1918         Respond("Replay timer paused vsyncId=" + std::to_string(vsyncId));
1919     }
1920     g_replayLastPauseTimeReported = recordPlayTime;
1921 }
1922 
1923 void RSProfiler::PlaybackPauseAt(const ArgList& args)
1924 {
1925     if (!IsPlaying()) {
1926         Respond("PlaybackPauseAt REJECT is_playing=false");
1927         return;
1928     }
1929 
1930     double pauseTime;
1931     if (args.String(0) == "VSYNC") {
1932         int64_t vsyncId = args.Int64(1);
1933         pauseTime = g_playbackFile.ConvertVsyncId2Time(vsyncId);
1934     } else {
1935         pauseTime = args.Fp64();
1936     }
1937 
1938     const uint64_t currentTime = RawNowNano();
1939     const double recordPlayTime = Utils::ToSeconds(PatchTime(currentTime)) - g_playbackStartTime;
1940     if (recordPlayTime > pauseTime) {
1941         return;
1942     }
1943 
1944     const uint64_t pauseTimeStart = currentTime + Utils::ToNanoseconds(pauseTime - recordPlayTime);
1945 
1946     TimePauseAt(currentTime, pauseTimeStart);
1947     ResetAnimationStamp();
1948     Respond("OK");
1949 }
1950 
1951 void RSProfiler::PlaybackPauseClear(const ArgList& args)
1952 {
1953     TimePauseClear();
1954     Respond("OK");
1955 }
1956 
1957 void RSProfiler::PlaybackResume(const ArgList& args)
1958 {
1959     if (!IsPlaying()) {
1960         return;
1961     }
1962 
1963     TimePauseResume(Utils::Now());
1964     ResetAnimationStamp();
1965     Respond("OK");
1966 }
1967 
1968 void RSProfiler::ProcessCommands()
1969 {
1970     if (g_playbackWaitFrames > 0) {
1971         g_playbackWaitFrames--;
1972         Respond("awake_frame(2) " + std::to_string(g_playbackWaitFrames));
1973         AwakeRenderServiceThread();
1974         return;
1975     }
1976 
1977     std::vector<std::string> line;
1978     if (Network::PopCommand(line)) {
1979         Invoke(line);
1980     }
1981 }
1982 
1983 uint32_t RSProfiler::GetFrameNumber()
1984 {
1985     return g_frameNumber;
1986 }
1987 
1988 void RSProfiler::BlinkNodeUpdate()
1989 {
1990     if (g_blinkSavedParentChildren.empty()) {
1991         return;
1992     }
1993 
1994     constexpr uint32_t blinkTotalCount = 20;
1995     constexpr uint32_t blinkFrameDelay = 5;
1996     const uint32_t blinkStage = g_blinkNodeCount / blinkFrameDelay;
1997     if (const bool isOdd = blinkStage % 2) {
1998         // restore node
1999         const auto parentNode = g_blinkSavedParentChildren[0];
2000         if (!parentNode) {
2001             return;
2002         }
2003         for (size_t i = 1; i < g_blinkSavedParentChildren.size(); i++) {
2004             const auto child = g_blinkSavedParentChildren[i];
2005             parentNode->RemoveChild(child);
2006             child->ResetParent();
2007         }
2008         for (size_t i = 1; i < g_blinkSavedParentChildren.size(); i++) {
2009             const auto child = g_blinkSavedParentChildren[i];
2010             parentNode->AddChild(child);
2011         }
2012         if (blinkStage > blinkTotalCount) {
2013             g_blinkNodeCount = 0;
2014             g_blinkSavedParentChildren.clear();
2015         }
2016     } else {
2017         // remove node
2018         const auto parentNode = g_blinkSavedParentChildren[0];
2019         auto blinkNode = GetRenderNode(g_blinkNodeId);
2020         parentNode->RemoveChild(blinkNode);
2021         blinkNode->ResetParent();
2022     }
2023 
2024     g_blinkNodeCount++;
2025     AwakeRenderServiceThread();
2026 }
2027 
2028 void RSProfiler::CalcPerfNodeUpdate()
2029 {
2030     if (g_calcPerfNode != 0 || g_nodeListPerfCalcIndex < 0) {
2031         return;
2032     }
2033 
2034     for (const auto& item : g_calcPerfSavedChildren) {
2035         const auto parentNode = item.first;
2036         if (!parentNode) {
2037             continue;
2038         }
2039         for (const auto& child : item.second) {
2040             parentNode->RemoveChild(child);
2041             child->ResetParent();
2042         }
2043         for (const auto& child : item.second) {
2044             parentNode->AddChild(child);
2045         }
2046     }
2047 
2048     if (g_calcPerfNodeTry != 0) {
2049         g_calcPerfNodeTry = 0;
2050         g_nodeListPerfCalcIndex++;
2051         CalcPerfNodeAllStep();
2052         return;
2053     }
2054 
2055     g_calcPerfSavedChildren.clear();
2056     g_calcPerfNodeTry++;
2057     AwakeRenderServiceThread();
2058 }
2059 
2060 } // namespace OHOS::Rosen