• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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 "core/common/layout_inspector.h"
17 
18 #ifdef USE_NEW_SKIA
19 #include "include/core/SkPixmap.h"
20 #include "include/core/SkData.h"
21 #include "include/encode/SkPngEncoder.h"
22 #include "src/base/SkBase64.h"
23 #else
24 #include "include/utils/SkBase64.h"
25 #endif
26 
27 #include "include/core/SkImage.h"
28 #include "include/core/SkString.h"
29 
30 #include "connect_server_manager.h"
31 
32 #include "adapter/ohos/osal/pixel_map_ohos.h"
33 #include "adapter/ohos/entrance/rs_adapter.h"
34 #include "adapter/ohos/entrance/subwindow/subwindow_ohos.h"
35 #include "base/log/ace_checker.h"
36 #include "base/subwindow/subwindow_manager.h"
37 #include "base/thread/background_task_executor.h"
38 #include "base/websocket/websocket_manager.h"
39 #include "core/common/ace_engine.h"
40 #include "core/common/connect_server_manager.h"
41 #include "core/components_ng/render/adapter/component_snapshot.h"
42 #include "core/components_ng/render/adapter/rosen_render_context.h"
43 #include "core/components_v2/inspector/inspector.h"
44 #include "render_service_client/core/pipeline/rs_node_map.h"
45 namespace OHOS::Ace {
46 
47 namespace {
48 constexpr size_t SNAP_PARTITION_SIZE = 100;
49 constexpr int64_t FIND_RSNODE_ERROR = -1;
50 constexpr int32_t UI_TREE = 0;
51 constexpr int32_t THREE_DIMENSIONS_TREE = 1;
52 constexpr int32_t QUERY_ABILITY = 2;
53 #ifndef USE_NEW_SKIA
54 constexpr int32_t PNG_ENCODE_QUALITY = 100;
55 #endif
ColorSpaceToSkColorSpace(const RefPtr<PixelMap> & pixmap)56 sk_sp<SkColorSpace> ColorSpaceToSkColorSpace(const RefPtr<PixelMap>& pixmap)
57 {
58     return SkColorSpace::MakeSRGB();
59 }
60 
AlphaTypeToSkAlphaType(const RefPtr<PixelMap> & pixmap)61 SkAlphaType AlphaTypeToSkAlphaType(const RefPtr<PixelMap>& pixmap)
62 {
63     switch (pixmap->GetAlphaType()) {
64         case AlphaType::IMAGE_ALPHA_TYPE_UNKNOWN:
65             return SkAlphaType::kUnknown_SkAlphaType;
66         case AlphaType::IMAGE_ALPHA_TYPE_OPAQUE:
67             return SkAlphaType::kOpaque_SkAlphaType;
68         case AlphaType::IMAGE_ALPHA_TYPE_PREMUL:
69             return SkAlphaType::kPremul_SkAlphaType;
70         case AlphaType::IMAGE_ALPHA_TYPE_UNPREMUL:
71             return SkAlphaType::kUnpremul_SkAlphaType;
72         default:
73             return SkAlphaType::kUnknown_SkAlphaType;
74     }
75 }
76 
PixelFormatToSkColorType(const RefPtr<PixelMap> & pixmap)77 SkColorType PixelFormatToSkColorType(const RefPtr<PixelMap>& pixmap)
78 {
79     switch (pixmap->GetPixelFormat()) {
80         case PixelFormat::RGB_565:
81             return SkColorType::kRGB_565_SkColorType;
82         case PixelFormat::RGBA_8888:
83             return SkColorType::kRGBA_8888_SkColorType;
84         case PixelFormat::BGRA_8888:
85             return SkColorType::kBGRA_8888_SkColorType;
86         case PixelFormat::ALPHA_8:
87             return SkColorType::kAlpha_8_SkColorType;
88         case PixelFormat::RGBA_F16:
89             return SkColorType::kRGBA_F16_SkColorType;
90         case PixelFormat::UNKNOWN:
91         case PixelFormat::ARGB_8888:
92         case PixelFormat::RGB_888:
93         case PixelFormat::NV21:
94         case PixelFormat::NV12:
95         case PixelFormat::CMYK:
96         default:
97             return SkColorType::kUnknown_SkColorType;
98     }
99 }
100 
MakeSkImageInfoFromPixelMap(const RefPtr<PixelMap> & pixmap)101 SkImageInfo MakeSkImageInfoFromPixelMap(const RefPtr<PixelMap>& pixmap)
102 {
103     SkColorType colorType = PixelFormatToSkColorType(pixmap);
104     SkAlphaType alphaType = AlphaTypeToSkAlphaType(pixmap);
105     sk_sp<SkColorSpace> colorSpace = ColorSpaceToSkColorSpace(pixmap);
106     return SkImageInfo::Make(pixmap->GetWidth(), pixmap->GetHeight(), colorType, alphaType, colorSpace);
107 }
108 
GetWindow(int32_t containerId)109 const OHOS::sptr<OHOS::Rosen::Window> GetWindow(int32_t containerId)
110 {
111     auto container = AceEngine::Get().GetContainer(containerId);
112     if (containerId >= MIN_SUBCONTAINER_ID && containerId < MIN_PLUGIN_SUBCONTAINER_ID) {
113         auto subwindow = SubwindowManager::GetInstance()->GetSubwindow(
114             SubwindowManager::GetInstance()->GetParentContainerId(containerId));
115         CHECK_NULL_RETURN(subwindow, nullptr);
116         if (AceType::InstanceOf<SubwindowOhos>(subwindow)) {
117             auto subWindowOhos = AceType::DynamicCast<SubwindowOhos>(subwindow);
118             CHECK_NULL_RETURN(subWindowOhos, nullptr);
119             return subWindowOhos->GetSubWindow();
120         }
121     } else {
122         auto aceContainer = AceType::DynamicCast<Platform::AceContainer>(container);
123         if (aceContainer != nullptr) {
124             return OHOS::Rosen::Window::Find(aceContainer->GetWindowName());
125         }
126         return OHOS::Rosen::Window::GetTopWindowWithId(container->GetWindowId());
127     }
128     return nullptr;
129 }
130 } // namespace
131 
132 static std::vector<std::string> inspectorAbilities = {"3DLayers"};
133 constexpr static char RECNODE_SELFID[] = "selfId";
134 constexpr static char RECNODE_NODEID[] = "nodeID";
135 constexpr static char RECNODE_PARENTID[] = "parentID";
136 constexpr static char RECNODE_NAME[] = "value";
137 constexpr static char RECNODE_DEBUGLINE[] = "debugLine";
138 constexpr static char RECNODE_CHILDREN[] = "RSNode";
139 constexpr static char ARK_DEBUGGER_LIB_PATH[] = "libark_connect_inspector.z.so";
140 static constexpr char START_PERFORMANCE_CHECK_MESSAGE[] = "StartArkPerformanceCheck";
141 static constexpr char END_PERFORMANCE_CHECK_MESSAGE[] = "EndArkPerformanceCheck";
142 
143 bool LayoutInspector::stateProfilerStatus_ = false;
144 bool LayoutInspector::layoutInspectorStatus_ = false;
145 bool LayoutInspector::isUseStageModel_ = false;
146 std::mutex LayoutInspector::recMutex_;
147 ProfilerStatusCallback LayoutInspector::jsStateProfilerStatusCallback_ = nullptr;
148 RsProfilerNodeMountCallback LayoutInspector::rsProfilerNodeMountCallback_ = nullptr;
149 const char PNG_TAG[] = "png";
150 NG::InspectorTreeMap LayoutInspector::recNodeInfos_;
151 std::once_flag LayoutInspector::loadFlag;
152 void* LayoutInspector::handlerConnectServerSo = nullptr;
153 LayoutInspector::SetArkUICallback LayoutInspector::setArkUICallback = nullptr;
154 
SupportInspector()155 void LayoutInspector::SupportInspector()
156 {
157     auto container = Container::Current();
158     CHECK_NULL_VOID(container);
159     if (!layoutInspectorStatus_) {
160         return;
161     }
162     std::string treeJsonStr;
163     GetInspectorTreeJsonStr(treeJsonStr, ContainerScope::CurrentId());
164     if (treeJsonStr.empty()) {
165         return;
166     }
167     auto message = JsonUtil::Create(true);
168     GetSnapshotJson(ContainerScope::CurrentId(), message);
169     CHECK_NULL_VOID(message);
170 
171     auto sendTask = [treeJsonStr, jsonSnapshotStr = message->ToString(), container]() {
172         if (container->IsUseStageModel()) {
173             WebSocketManager::SendInspector(treeJsonStr, jsonSnapshotStr);
174         } else {
175             OHOS::Ace::ConnectServerManager::Get().SendInspector(treeJsonStr, jsonSnapshotStr);
176         }
177     };
178     BackgroundTaskExecutor::GetInstance().PostTask(std::move(sendTask));
179 }
180 
SetStatus(bool layoutInspectorStatus)181 void LayoutInspector::SetStatus(bool layoutInspectorStatus)
182 {
183     layoutInspectorStatus_ = layoutInspectorStatus;
184 }
185 
TriggerJsStateProfilerStatusCallback(bool status)186 void LayoutInspector::TriggerJsStateProfilerStatusCallback(bool status)
187 {
188     if (jsStateProfilerStatusCallback_) {
189         stateProfilerStatus_ = status;
190         jsStateProfilerStatusCallback_(status);
191     }
192 }
193 
SetJsStateProfilerStatusCallback(ProfilerStatusCallback && callback)194 void LayoutInspector::SetJsStateProfilerStatusCallback(ProfilerStatusCallback&& callback)
195 {
196     jsStateProfilerStatusCallback_ = callback;
197 }
198 
GetStateProfilerStatus()199 bool LayoutInspector::GetStateProfilerStatus()
200 {
201     return stateProfilerStatus_;
202 }
203 
GetRsProfilerNodeMountCallback()204 RsProfilerNodeMountCallback LayoutInspector::GetRsProfilerNodeMountCallback()
205 {
206     return rsProfilerNodeMountCallback_;
207 }
208 
SetRsProfilerNodeMountCallback(RsProfilerNodeMountCallback && callback)209 void LayoutInspector::SetRsProfilerNodeMountCallback(RsProfilerNodeMountCallback&& callback)
210 {
211     rsProfilerNodeMountCallback_ = callback;
212 }
213 
SendMessage(const std::string & message)214 void LayoutInspector::SendMessage(const std::string& message)
215 {
216     WebSocketManager::SendMessage(message);
217 }
218 
SetStateProfilerStatus(bool status)219 void LayoutInspector::SetStateProfilerStatus(bool status)
220 {
221     auto taskExecutor = Container::CurrentTaskExecutorSafely();
222     CHECK_NULL_VOID(taskExecutor);
223     auto task = [status]() { LayoutInspector::TriggerJsStateProfilerStatusCallback(status); };
224     taskExecutor->PostTask(std::move(task), TaskExecutor::TaskType::UI, "ArkUISetStateProfilerStatus");
225 }
226 
ConnectServerCallback()227 void LayoutInspector::ConnectServerCallback()
228 {
229     TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR, "connect server callback isStage:%{public}d", isUseStageModel_);
230     if (isUseStageModel_) {
231         TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR, "connect server, reset callback.");
232         WebSocketManager::SetRecordCallback(LayoutInspector::HandleStartRecord, LayoutInspector::HandleStopRecord);
233     }
234 }
235 
SetCallback(int32_t instanceId)236 void LayoutInspector::SetCallback(int32_t instanceId)
237 {
238     TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR, "InstanceId:%{public}d", instanceId);
239     auto container = AceEngine::Get().GetContainer(instanceId);
240     CHECK_NULL_VOID(container);
241     if (container->IsUseStageModel()) {
242         WebSocketManager::SetProfilerCallBack([](bool status) { return SetStateProfilerStatus(status); });
243         WebSocketManager::SetSwitchCallback(
244             [](int32_t containerId) { return CreateLayoutInfo(containerId); }, instanceId);
245         WebSocketManager::SetRecordCallback(LayoutInspector::HandleStartRecord, LayoutInspector::HandleStopRecord);
246         WebSocketManager::RegisterConnectServerCallback(LayoutInspector::ConnectServerCallback);
247         isUseStageModel_ = true;
248         RegisterConnectCallback();
249     } else {
250         OHOS::Ace::ConnectServerManager::Get().SetLayoutInspectorCallback(
251             [](int32_t containerId) { return CreateLayoutInfo(containerId); });
252         isUseStageModel_ = false;
253     }
254 
255     SendInstanceMessageCallBack sendInstanceMessageCallBack = [](int32_t id) {
256         WebSocketManager::SetProfilerCallBack(
257             [](bool status) { return SetStateProfilerStatus(status); });
258         WebSocketManager::SetSwitchCallback([](int32_t containerId) { return CreateLayoutInfo(containerId); }, id);
259     };
260     WebSocketManager::RegisterSendInstanceMessageCallback(sendInstanceMessageCallBack);
261 }
262 
CreateContainerLayoutInfo(RefPtr<Container> & container)263 void LayoutInspector::CreateContainerLayoutInfo(RefPtr<Container>& container)
264 {
265     CHECK_NULL_VOID(container);
266     if (container->IsDynamicRender()) {
267         container = Container::CurrentSafely();
268         CHECK_NULL_VOID(container);
269     }
270     int32_t containerId = container->GetInstanceId();
271     ContainerScope socpe(containerId);
272     auto context = PipelineContext::GetCurrentContext();
273     CHECK_NULL_VOID(context);
274     auto getInspectorTask = [container, containerId]() {
275         std::string treeJson;
276         GetInspectorTreeJsonStr(treeJson, containerId);
277         auto message = JsonUtil::Create(true);
278         GetSnapshotJson(containerId, message);
279         CHECK_NULL_VOID(message);
280         auto sendResultTask = [treeJsonStr = std::move(treeJson), jsonSnapshotStr = message->ToString(), container]() {
281             if (container->IsUseStageModel()) {
282                 WebSocketManager::SendInspector(treeJsonStr, jsonSnapshotStr);
283             } else {
284                 OHOS::Ace::ConnectServerManager::Get().SendInspector(treeJsonStr, jsonSnapshotStr);
285             }
286         };
287         BackgroundTaskExecutor::GetInstance().PostTask(std::move(sendResultTask));
288     };
289     context->GetTaskExecutor()->PostTask(
290         std::move(getInspectorTask), TaskExecutor::TaskType::UI, "ArkUIGetInspectorTreeJson");
291 }
292 
CreateContainer3DLayoutInfo(RefPtr<Container> & container)293 void LayoutInspector::CreateContainer3DLayoutInfo(RefPtr<Container>& container)
294 {
295     CHECK_NULL_VOID(container);
296     if (container->IsDynamicRender()) {
297         container = Container::CurrentSafely();
298         CHECK_NULL_VOID(container);
299     }
300     int32_t containerId = container->GetInstanceId();
301     ContainerScope scope(containerId);
302     auto pipelineContext = container->GetPipelineContext();
303     CHECK_NULL_VOID(pipelineContext);
304     auto ngPipeline = AceType::DynamicCast<NG::PipelineContext>(pipelineContext);
305     CHECK_NULL_VOID(ngPipeline);
306     auto getInspectorTask = [containerId, weakPipeline = AceType::WeakClaim(AceType::RawPtr(ngPipeline))]() {
307         std::string treeJson;
308         GetInspectorTreeJsonStr(treeJson, containerId);
309         auto sendJsonTreeTask = [treeJsonStr = std::move(treeJson)]() {
310             WebSocketManager::SendMessage(treeJsonStr);
311         };
312         BackgroundTaskExecutor::GetInstance().PostTask(std::move(sendJsonTreeTask));
313 
314         auto pipeline = weakPipeline.Upgrade();
315         CHECK_NULL_VOID(pipeline);
316         auto root = pipeline->GetRootElement();
317         CHECK_NULL_VOID(root);
318         Get3DSnapshotJson(root);
319     };
320     pipelineContext->GetTaskExecutor()->PostTask(
321         std::move(getInspectorTask), TaskExecutor::TaskType::UI, "ArkUIGetInspector3DTreeJson");
322 }
323 
CreateLayoutInfo(int32_t containerId)324 void LayoutInspector::CreateLayoutInfo(int32_t containerId)
325 {
326     auto container = Container::GetFocused();
327     return CreateContainerLayoutInfo(container);
328 }
329 
CreateLayoutInfoByWinId(uint32_t windId)330 void LayoutInspector::CreateLayoutInfoByWinId(uint32_t windId)
331 {
332     auto container = Container::GetByWindowId(windId);
333     if (container) {
334         TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR, "start get container %{public}d info", container->GetInstanceId());
335     }
336     return CreateContainerLayoutInfo(container);
337 }
338 
SendInspctorAbilities()339 void LayoutInspector::SendInspctorAbilities()
340 {
341     auto jsonRoot = JsonUtil::Create(true);
342     jsonRoot->Put("type", "inspectorAbilities");
343     auto contentArray = JsonUtil::CreateArray(true);
344     for (size_t i = 0; i < inspectorAbilities.size(); ++i) {
345         contentArray->Put(std::to_string(i).c_str(), inspectorAbilities[i].c_str());
346     }
347     jsonRoot->PutRef("content", std::move(contentArray));
348     auto sendInspctorAbilitiesTask = [abilitiesJsonStr = jsonRoot->ToString()]() {
349         WebSocketManager::SendMessage(abilitiesJsonStr);
350     };
351     BackgroundTaskExecutor::GetInstance().PostTask(std::move(sendInspctorAbilitiesTask));
352 }
353 
Create3DLayoutInfoByWinId(uint32_t windId)354 void LayoutInspector::Create3DLayoutInfoByWinId(uint32_t windId)
355 {
356     auto container = Container::GetByWindowId(windId);
357     if (container) {
358         TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR, "start get container %{public}d info", container->GetInstanceId());
359     }
360     return CreateContainer3DLayoutInfo(container);
361 }
362 
GetInspectorTreeJsonStr(std::string & treeJsonStr,int32_t containerId)363 void LayoutInspector::GetInspectorTreeJsonStr(std::string& treeJsonStr, int32_t containerId)
364 {
365     auto container = AceEngine::Get().GetContainer(containerId);
366     CHECK_NULL_VOID(container);
367 #ifdef NG_BUILD
368     treeJsonStr = NG::Inspector::GetInspector(true);
369 #else
370     if (container->IsUseNewPipeline()) {
371         if (containerId >= MIN_SUBCONTAINER_ID && containerId < MIN_PLUGIN_SUBCONTAINER_ID) {
372             treeJsonStr = NG::Inspector::GetSubWindowInspector(true);
373         } else {
374             treeJsonStr = NG::Inspector::GetInspector(true);
375         }
376     } else {
377         auto pipelineContext = AceType::DynamicCast<PipelineContext>(container->GetPipelineContext());
378         CHECK_NULL_VOID(pipelineContext);
379         treeJsonStr = V2::Inspector::GetInspectorTree(pipelineContext, true);
380     }
381 #endif
382 }
383 
BuildInfoForIDE(uint64_t id,const std::shared_ptr<Media::PixelMap> & pixelMap,std::unique_ptr<JsonValue> & message)384 void LayoutInspector::BuildInfoForIDE(uint64_t id, const std::shared_ptr<Media::PixelMap>& pixelMap,
385     std::unique_ptr<JsonValue>& message)
386 {
387     CHECK_NULL_VOID(pixelMap);
388     auto acePixelMap = AceType::MakeRefPtr<PixelMapOhos>(pixelMap);
389     auto imageInfo = MakeSkImageInfoFromPixelMap(acePixelMap);
390     SkPixmap imagePixmap(
391         imageInfo, reinterpret_cast<const void*>(acePixelMap->GetPixels()), acePixelMap->GetRowBytes());
392     sk_sp<SkImage> image;
393 #ifdef USE_NEW_SKIA
394     image = SkImages::RasterFromPixmap(imagePixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(acePixelMap));
395     CHECK_NULL_VOID(image);
396     auto data = image->refEncodedData();
397     if (!data) {
398         data = SkPngEncoder::Encode(nullptr, image.get(), {});
399     }
400 #else
401     image = SkImage::MakeFromRaster(imagePixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(acePixelMap));
402     CHECK_NULL_VOID(image);
403     auto data = image->encodeToData(SkEncodedImageFormat::kPNG, PNG_ENCODE_QUALITY);
404 #endif
405     CHECK_NULL_VOID(data);
406     auto defaultDisplay = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
407     CHECK_NULL_VOID(defaultDisplay);
408     auto deviceDpi = defaultDisplay->GetDpi();
409     auto deviceWidth = defaultDisplay->GetWidth();
410     auto deviceHeight = defaultDisplay->GetHeight();
411     message->Put("$ID", RsNodeIdToFrameNodeId(id));
412     message->Put("format", PNG_TAG);
413     message->Put("width", (*pixelMap).GetWidth());
414     message->Put("height", (*pixelMap).GetHeight());
415     message->Put("deviceWidth", deviceWidth);
416     message->Put("deviceHeight", deviceHeight);
417     message->Put("deviceDpi", deviceDpi);
418     int32_t encodeLength = static_cast<int32_t>(SkBase64::Encode(data->data(), data->size(), nullptr));
419     message->Put("size", data->size());
420     SkString info(encodeLength);
421 #ifdef USE_NEW_SKIA
422     SkBase64::Encode(data->data(), data->size(), info.data());
423 #else
424     SkBase64::Encode(data->data(), data->size(), info.writable_str());
425 #endif
426     message->Put("pixelMapBase64", info.c_str());
427 }
428 
RsNodeIdToFrameNodeId(uint64_t rsNodeId)429 int64_t LayoutInspector::RsNodeIdToFrameNodeId(uint64_t rsNodeId)
430 {
431     auto context = PipelineContext::GetCurrentContext();
432     auto rsUIContext = RsAdapter::GetRSUIContext(context);
433     auto rsNode = rsUIContext ? rsUIContext->GetNodeMap().GetNode(rsNodeId)
434                     : Rosen::RSNodeMap::Instance().GetNode(rsNodeId);
435     if (rsNode == nullptr) {
436         return FIND_RSNODE_ERROR;
437     }
438     return rsNode->GetFrameNodeId();
439 }
440 
Filter3DSnapshot(const std::vector<PixelMapPair> & snapinfos)441 std::vector<PixelMapPair> LayoutInspector::Filter3DSnapshot(const std::vector<PixelMapPair>& snapinfos)
442 {
443     std::vector<PixelMapPair> infos;
444     for (const auto& snapInfo : snapinfos) {
445         if (snapInfo.second) {
446             infos.emplace_back(snapInfo);
447         }
448     }
449     return infos;
450 }
451 
SendEmpty3DSnapJson()452 void LayoutInspector::SendEmpty3DSnapJson()
453 {
454     TAG_LOGI(AceLogTag::ACE_LAYOUT_INSPECTOR, "SendEmpty3DSnapJson");
455     auto message = JsonUtil::Create(true);
456     CHECK_NULL_VOID(message);
457     auto contentMessage = JsonUtil::CreateArray(true);
458     CHECK_NULL_VOID(contentMessage);
459     message->Put("type", "3DLayers");
460     message->Put("totalParts", 1);
461     message->Put("partNum", 1);
462     message->Put("LayersCount", 0);
463     message->PutRef("content", std::move(contentMessage));
464     auto sendTask = [jsonSnapshotStr = message->ToString()]() {
465         WebSocketManager::SendMessage(jsonSnapshotStr);
466     };
467     BackgroundTaskExecutor::GetInstance().PostTask(std::move(sendTask));
468 }
469 
Get3DSnapshotJson(const RefPtr<NG::FrameNode> & node)470 void LayoutInspector::Get3DSnapshotJson(const RefPtr<NG::FrameNode>& node)
471 {
472     std::vector<PixelMapPair> snapInfos = NG::ComponentSnapshot::GetSoloNode(node);
473     TAG_LOGI(AceLogTag::ACE_LAYOUT_INSPECTOR, "3d snapInfos size:%{public}zu", snapInfos.size());
474     auto filterSnapInfos = Filter3DSnapshot(snapInfos);
475     TAG_LOGI(AceLogTag::ACE_LAYOUT_INSPECTOR, "3d snapInfos after filter size:%{public}zu", filterSnapInfos.size());
476     if (filterSnapInfos.empty()) {
477         SendEmpty3DSnapJson();
478         return;
479     }
480     size_t totalParts = (filterSnapInfos.size() + SNAP_PARTITION_SIZE - 1) / SNAP_PARTITION_SIZE;
481     int partNum = 1;
482     for (size_t i = 0; i < filterSnapInfos.size(); i += SNAP_PARTITION_SIZE) {
483         auto message = JsonUtil::Create(true);
484         CHECK_NULL_VOID(message);
485         auto contentMessage = JsonUtil::CreateArray(true);
486         CHECK_NULL_VOID(contentMessage);
487         message->Put("type", "3DLayers");
488         message->Put("totalParts", totalParts);
489         message->Put("partNum", partNum++);
490         message->Put("LayersCount", filterSnapInfos.size());
491 
492         for (size_t j = i; j < i + SNAP_PARTITION_SIZE && j < filterSnapInfos.size(); j++) {
493             auto snapInfo = filterSnapInfos[j];
494             auto snapPixelMap = snapInfo.second;
495             if (snapPixelMap) {
496                 auto snapInfoJson = JsonUtil::Create(true);
497                 BuildInfoForIDE(snapInfo.first, snapPixelMap, snapInfoJson);
498                 contentMessage->PutRef(std::move(snapInfoJson));
499             }
500         }
501 
502         message->PutRef("content", std::move(contentMessage));
503         auto sendTask = [jsonSnapshotStr = message->ToString()]() {
504                 WebSocketManager::SendMessage(jsonSnapshotStr);
505             };
506         BackgroundTaskExecutor::GetInstance().PostTask(std::move(sendTask));
507     }
508 }
509 
GetSnapshotJson(int32_t containerId,std::unique_ptr<JsonValue> & message)510 void LayoutInspector::GetSnapshotJson(int32_t containerId, std::unique_ptr<JsonValue>& message)
511 {
512     auto container = AceEngine::Get().GetContainer(containerId);
513     CHECK_NULL_VOID(container);
514     OHOS::sptr<OHOS::Rosen::Window> window = GetWindow(containerId);
515     CHECK_NULL_VOID(window);
516     auto pixelMap = window->Snapshot();
517     CHECK_NULL_VOID(pixelMap);
518     auto acePixelMap = AceType::MakeRefPtr<PixelMapOhos>(pixelMap);
519     CHECK_NULL_VOID(acePixelMap);
520     auto imageInfo = MakeSkImageInfoFromPixelMap(acePixelMap);
521     SkPixmap imagePixmap(
522         imageInfo, reinterpret_cast<const void*>(acePixelMap->GetPixels()), acePixelMap->GetRowBytes());
523     sk_sp<SkImage> image;
524 #ifdef USE_NEW_SKIA
525     image = SkImages::RasterFromPixmap(imagePixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(acePixelMap));
526     CHECK_NULL_VOID(image);
527     auto data = image->refEncodedData();
528     if (!data) {
529         data = SkPngEncoder::Encode(nullptr, image.get(), {});
530     }
531 #else
532     image = SkImage::MakeFromRaster(imagePixmap, &PixelMap::ReleaseProc, PixelMap::GetReleaseContext(acePixelMap));
533     CHECK_NULL_VOID(image);
534     auto data = image->encodeToData(SkEncodedImageFormat::kPNG, 100);
535 #endif
536     CHECK_NULL_VOID(data);
537     auto defaultDisplay = Rosen::DisplayManager::GetInstance().GetDefaultDisplay();
538     CHECK_NULL_VOID(defaultDisplay);
539     auto deviceDpi = defaultDisplay->GetDpi();
540     auto deviceWidth = defaultDisplay->GetWidth();
541     auto deviceHeight = defaultDisplay->GetHeight();
542     message->Put("type", "snapShot");
543     message->Put("format", PNG_TAG);
544     message->Put("width", (*pixelMap).GetWidth());
545     message->Put("height", (*pixelMap).GetHeight());
546     message->Put("posX", container->GetViewPosX());
547     message->Put("posY", container->GetViewPosY());
548     message->Put("deviceWidth", deviceWidth);
549     message->Put("deviceHeight", deviceHeight);
550     message->Put("deviceDpi", deviceDpi);
551     int32_t encodeLength = static_cast<int32_t>(SkBase64::Encode(data->data(), data->size(), nullptr));
552     message->Put("size", data->size());
553     SkString info(encodeLength);
554 #ifdef USE_NEW_SKIA
555     SkBase64::Encode(data->data(), data->size(), info.data());
556 #else
557     SkBase64::Encode(data->data(), data->size(), info.writable_str());
558 #endif
559     message->Put("pixelMapBase64", info.c_str());
560 }
561 
RegisterConnectCallback()562 void LayoutInspector::RegisterConnectCallback()
563 {
564     std::call_once(loadFlag, []() {
565         handlerConnectServerSo = dlopen(ARK_DEBUGGER_LIB_PATH, RTLD_NOLOAD | RTLD_NOW);
566         if (handlerConnectServerSo == nullptr) {
567             handlerConnectServerSo = dlopen(ARK_DEBUGGER_LIB_PATH, RTLD_NOW);
568             if (handlerConnectServerSo == nullptr) {
569                 TAG_LOGE(AceLogTag::ACE_LAYOUT_INSPECTOR, "null handlerConnectServerSo: %{public}s", dlerror());
570                 return;
571             }
572         }
573 
574         setArkUICallback = reinterpret_cast<SetArkUICallback>(dlsym(handlerConnectServerSo, "SetArkUICallback"));
575         if (setArkUICallback == nullptr) {
576             TAG_LOGE(AceLogTag::ACE_LAYOUT_INSPECTOR, "null setArkUICallback: %{public}s", dlerror());
577             return;
578         }
579     });
580 
581     if (setArkUICallback != nullptr) {
582         setArkUICallback([](const char* message) { ProcessMessages(message); });
583     }
584 }
585 
ProcessMessages(const std::string & message)586 std::pair<uint32_t, int32_t> LayoutInspector::ProcessMessages(const std::string& message)
587 {
588     if (message.find(START_PERFORMANCE_CHECK_MESSAGE, 0) != std::string::npos) {
589         TAG_LOGI(AceLogTag::ACE_LAYOUT_INSPECTOR, "performance check start");
590         AceChecker::SetPerformanceCheckStatus(true, message);
591     } else if (message.find(END_PERFORMANCE_CHECK_MESSAGE, 0) != std::string::npos) {
592         TAG_LOGI(AceLogTag::ACE_LAYOUT_INSPECTOR, "performance check end");
593         AceChecker::SetPerformanceCheckStatus(false, message);
594     }
595     auto windowResult = NG::Inspector::ParseWindowIdFromMsg(message);
596     uint32_t windowId = windowResult.first;
597     if (windowId == OHOS::Ace::NG::INVALID_WINDOW_ID && windowResult.second != QUERY_ABILITY) {
598         TAG_LOGE(AceLogTag::ACE_LAYOUT_INSPECTOR, "input message: %{public}s", message.c_str());
599         return windowResult;
600     }
601 
602     switch (windowResult.second) {
603         case UI_TREE:
604             CreateLayoutInfoByWinId(windowId);
605             break;
606         case THREE_DIMENSIONS_TREE:
607             Create3DLayoutInfoByWinId(windowId);
608             break;
609         case QUERY_ABILITY:
610             SendInspctorAbilities();
611             break;
612         default:
613             TAG_LOGE(AceLogTag::ACE_LAYOUT_INSPECTOR, "unsupport message: %{public}s", message.c_str());
614             break;
615     }
616     return windowResult;
617 }
618 
HandleStopRecord()619 void LayoutInspector::HandleStopRecord()
620 {
621     std::unique_lock<std::mutex> lock(recMutex_);
622     SetRsProfilerNodeMountCallback(nullptr);
623     auto jsonRoot = JsonUtil::Create(true);
624     auto jsonNodeArray = JsonUtil::CreateArray(true);
625     for (auto& uiNode : recNodeInfos_) {
626         if (uiNode.second != nullptr) {
627             auto jsonNode = JsonUtil::Create(true);
628             jsonNode->Put(RECNODE_NODEID, std::to_string(uiNode.second->GetSelfId()).c_str());
629             jsonNode->Put(RECNODE_PARENTID, uiNode.second->GetParentId());
630             jsonNode->Put(RECNODE_SELFID, uiNode.second->GetNodeId());
631             jsonNode->Put(RECNODE_NAME, uiNode.second->GetName().c_str());
632             jsonNode->Put(RECNODE_DEBUGLINE, uiNode.second->GetDebugLine().c_str());
633             jsonNodeArray->PutRef(std::move(jsonNode));
634         }
635     }
636     recNodeInfos_.clear();
637     lock.unlock();
638     if (jsonNodeArray->GetArraySize()) {
639         jsonRoot->PutRef(RECNODE_CHILDREN, std::move(jsonNodeArray));
640     }
641     std::string arrayJsonStr = jsonRoot->ToString();
642     auto sendResultTask = [arrayJsonStr]() {
643         WebSocketManager::SetRecordResults(arrayJsonStr);
644     };
645     BackgroundTaskExecutor::GetInstance().PostTask(std::move(sendResultTask));
646 }
647 
HandleStartRecord()648 void LayoutInspector::HandleStartRecord()
649 {
650     // regist inner callback function
651     std::unique_lock<std::mutex> lock(recMutex_);
652     SetRsProfilerNodeMountCallback(LayoutInspector::HandleInnerCallback);
653     lock.unlock();
654     auto container = Container::GetFocused();
655     CHECK_NULL_VOID(container);
656     if (container->IsDynamicRender()) {
657         container = Container::CurrentSafely();
658         CHECK_NULL_VOID(container);
659     }
660     auto containerId = container->GetInstanceId();
661     ContainerScope socpe(containerId);
662     auto context = PipelineContext::GetCurrentContext();
663     CHECK_NULL_VOID(context);
664     auto startRecordTask = []() {
665         std::lock_guard<std::mutex> lock(LayoutInspector::recMutex_);
666         NG::InspectorTreeMap recTreeNodes;
667         NG::InspectorTreeMap offScreenTreeNodes;
668         NG::Inspector::GetRecordAllPagesNodes(recTreeNodes);
669         TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR, "Get nodes size:%{public}zu", recTreeNodes.size());
670         NG::Inspector::GetOffScreenTreeNodes(offScreenTreeNodes);
671         TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR, "Get offscreen nodes size:%{public}zu", offScreenTreeNodes.size());
672         LayoutInspector::recNodeInfos_.swap(recTreeNodes);
673         for (auto& item : offScreenTreeNodes) {
674             recNodeInfos_.emplace(item);
675         }
676     };
677     context->GetTaskExecutor()->PostTask(
678         std::move(startRecordTask), TaskExecutor::TaskType::UI, "ArkUIGetInspectorTree");
679 }
680 
HandleInnerCallback(FrameNodeInfo node)681 void LayoutInspector::HandleInnerCallback(FrameNodeInfo node)
682 {
683     // convert FrameNodeInfo --> recNode
684     TAG_LOGD(AceLogTag::ACE_LAYOUT_INSPECTOR,
685         "FrameNodeInfo:selfid:%{public}" PRIu64 ",nodid:%{public}d,type:%{public}s,debugline:%{public}s",
686         node.rsNodeId, node.frameNodeId, node.nodeType.c_str(), node.debugline.c_str());
687     auto recNode = AceType::MakeRefPtr<NG::RecNode>();
688     CHECK_NULL_VOID(recNode);
689     recNode->SetSelfId(node.rsNodeId);
690     recNode->SetNodeId(node.frameNodeId);
691     recNode->SetName(node.nodeType);
692     recNode->SetDebugLine(node.debugline);
693     recNode->SetParentId(node.parentNodeId);
694     std::lock_guard<std::mutex> lock(recMutex_);
695     recNodeInfos_.emplace(node.rsNodeId, recNode);
696 }
697 } // namespace OHOS::Ace
698