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