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