1 /*
2 * Copyright (c) 2023-2025 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 "connect_inspector.h"
17
18 #include <mutex>
19
20 #include "common/log_wrapper.h"
21 #include "tooling/dynamic/base/pt_json.h"
22 #include "ws_server.h"
23
24 namespace OHOS::ArkCompiler::Toolchain {
25 using panda::ecmascript::tooling::PtJson;
26 using panda::ecmascript::tooling::Result;
27 std::mutex g_connectMutex;
28 std::unique_ptr<ConnectInspector> g_inspector = nullptr;
29 static constexpr char CONNECTED_MESSAGE[] = "connected";
30 static constexpr char REQUEST_MESSAGE[] = "tree";
31 static constexpr char STOPDEBUGGER_MESSAGE[] = "stopDebugger";
32 static constexpr char OPEN_ARKUI_STATE_PROFILER[] = "ArkUIStateProfilerOpen";
33 static constexpr char CLOSE_ARKUI_STATE_PROFILER[] = "ArkUIStateProfilerClose";
34 static constexpr char START_RECORD_MESSAGE[] = "rsNodeStartRecord";
35 static constexpr char STOP_RECORD_MESSAGE[] = "rsNodeStopRecord";
36 std::function<void(bool)> g_setConnectCallBack;
37
HandleDebugManager(void * const server)38 void* HandleDebugManager(void* const server)
39 {
40 if (server == nullptr) {
41 LOGE("HandleDebugManager server nullptr");
42 return nullptr;
43 }
44 #if defined(IOS_PLATFORM) || defined(MAC_PLATFORM)
45 pthread_setname_np("OS_DbgConThread");
46 #else
47 pthread_setname_np(pthread_self(), "OS_DbgConThread");
48 #endif
49
50 static_cast<ConnectServer*>(server)->RunServer();
51 return nullptr;
52 }
53
OnConnectedMessage(const std::string & message)54 void OnConnectedMessage(const std::string& message)
55 {
56 if (message.find(CONNECTED_MESSAGE, 0) != std::string::npos) {
57 g_inspector->waitingForDebugger_ = false;
58 if (g_setConnectCallBack != nullptr) {
59 g_setConnectCallBack(true);
60 }
61 for (auto& info : g_inspector->infoBuffer_) {
62 g_inspector->connectServer_->SendMessage(info.second);
63 }
64 }
65 }
66
OnInspectorRecordMessage(const std::string & message)67 void OnInspectorRecordMessage(const std::string& message)
68 {
69 if (message.find(START_RECORD_MESSAGE, 0) != std::string::npos) {
70 if (g_inspector->startRecord_ != nullptr && !g_inspector->isRecording_) {
71 LOGI("record start");
72 g_inspector->startRecord_();
73 g_inspector->isRecording_ = true;
74 }
75 }
76
77 if (message.find(STOP_RECORD_MESSAGE, 0) != std::string::npos) {
78 if (g_inspector->stopRecord_ != nullptr && g_inspector->isRecording_) {
79 LOGI("record stop");
80 g_inspector->stopRecord_();
81 g_inspector->isRecording_ = false;
82 }
83 }
84 }
85
OnArkUIInspectorMessage(const std::string & message)86 bool OnArkUIInspectorMessage(const std::string &message)
87 {
88 ConnectRequest request(message);
89 if (!request.IsValid()) {
90 return false;
91 }
92 std::string domain = request.GetDomain();
93 if (domain == "ArkUI") {
94 if (g_inspector->arkUICallback_ != nullptr) {
95 LOGI("OnArkUIInspectorMessage, arkUICallback_ called");
96 g_inspector->arkUICallback_(message.c_str());
97 } else {
98 LOGE("OnArkUIInspectorMessage, arkUICallback_ is nullptr");
99 }
100 return true;
101 } else if (domain == "WMS") {
102 if (g_inspector->wMSCallback_ != nullptr) {
103 LOGI("OnArkUIInspectorMessage, wMSCallback_ called");
104 g_inspector->wMSCallback_(message.c_str());
105 } else {
106 LOGE("OnArkUIInspectorMessage, wMSCallback_ is nullptr");
107 }
108 return true;
109 } else {
110 LOGW("OnArkUIInspectorMessage, unknown request");
111 }
112 return false;
113 }
114
OnCangjieInspectorMessage(const std::string & message)115 bool OnCangjieInspectorMessage(const std::string &message)
116 {
117 if (message.find("cangjie profiler") != std::string::npos) {
118 if (g_inspector->cangjieCallback_ != nullptr) {
119 LOGI("OnCangjieInspectorMessage, cangjieCallback_ called");
120 g_inspector->cangjieCallback_(message, SendMessage);
121 } else {
122 LOGE("OnCangjieInspectorMessage, cangjieCallback_ is nullptr");
123 }
124 return true;
125 } else {
126 LOGW("OnCangjieInspectorMessage. unknown request");
127 }
128 return false;
129 }
130
OnMessage(const std::string & message)131 void OnMessage(const std::string &message)
132 {
133 std::lock_guard<std::mutex> lock(g_connectMutex);
134 if (message.empty()) {
135 LOGE("message is empty");
136 return;
137 }
138
139 LOGI("ConnectServer OnMessage: %{public}s", message.c_str());
140 if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr) {
141 OnConnectedMessage(message);
142 if (OnArkUIInspectorMessage(message)) {
143 return;
144 }
145 if (OnCangjieInspectorMessage(message)) {
146 return;
147 }
148 if (message.find(OPEN_ARKUI_STATE_PROFILER, 0) != std::string::npos) {
149 if (g_inspector->setArkUIStateProfilerStatus_ != nullptr) {
150 LOGI("state profiler open");
151 g_inspector->setArkUIStateProfilerStatus_(true);
152 }
153 }
154 if (message.find(CLOSE_ARKUI_STATE_PROFILER, 0) != std::string::npos) {
155 if (g_inspector->setArkUIStateProfilerStatus_ != nullptr) {
156 LOGI("state profiler close");
157 g_inspector->setArkUIStateProfilerStatus_(false);
158 }
159 }
160 if (message.find(REQUEST_MESSAGE, 0) != std::string::npos) {
161 if (g_inspector->createLayoutInfo_ != nullptr) {
162 LOGI("tree start");
163 g_inspector->createLayoutInfo_(g_inspector->instanceId_);
164 }
165 }
166 if (message.find(STOPDEBUGGER_MESSAGE, 0) != std::string::npos) {
167 g_inspector->waitingForDebugger_ = true;
168 if (g_inspector->setDebugMode_ != nullptr) {
169 LOGI("stopDebugger start");
170 g_inspector->setDebugMode_();
171 }
172 if (g_setConnectCallBack != nullptr) {
173 g_setConnectCallBack(false);
174 }
175 }
176 OnInspectorRecordMessage(message);
177 }
178 }
179
SetSwitchCallBack(const std::function<void (int32_t)> & createLayoutInfo,int32_t instanceId)180 void SetSwitchCallBack(const std::function<void(int32_t)>& createLayoutInfo, int32_t instanceId)
181 {
182 std::lock_guard<std::mutex> lock(g_connectMutex);
183 if (g_inspector == nullptr) {
184 g_inspector = std::make_unique<ConnectInspector>();
185 }
186 g_inspector->createLayoutInfo_ = createLayoutInfo;
187 g_inspector->instanceId_ = instanceId;
188 }
189
SetConnectCallback(const std::function<void (bool)> & callback)190 void SetConnectCallback(const std::function<void(bool)>& callback)
191 {
192 g_setConnectCallBack = callback;
193 }
194
195 // stop debugger but the application continues to run
SetDebugModeCallBack(const std::function<void ()> & setDebugMode)196 void SetDebugModeCallBack(const std::function<void()>& setDebugMode)
197 {
198 std::lock_guard<std::mutex> lock(g_connectMutex);
199 if (g_inspector != nullptr) {
200 g_inspector->setDebugMode_ = setDebugMode;
201 }
202 }
203
ResetService()204 void ResetService()
205 {
206 if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr) {
207 g_inspector->connectServer_->StopServer();
208 g_inspector->connectServer_.reset();
209 }
210 }
211
StartServerForSocketPair(int socketfd)212 bool StartServerForSocketPair(int socketfd)
213 {
214 LOGI("StartServerForSocketPair, socketfd = %{private}d", socketfd);
215 if (g_inspector == nullptr) {
216 g_inspector = std::make_unique<ConnectInspector>();
217 }
218 if (g_inspector->connectServer_ != nullptr) {
219 LOGW("ConnectServer is not nullptr!");
220 return true;
221 }
222 g_inspector->connectServer_ = std::make_unique<ConnectServer>(socketfd,
223 std::bind(&OnMessage, std::placeholders::_1));
224
225 pthread_t tid;
226 if (pthread_create(&tid, nullptr, &HandleDebugManager,
227 static_cast<void*>(g_inspector->connectServer_.get())) != 0) {
228 LOGE("pthread_create fail!");
229 ResetService();
230 return false;
231 }
232 return true;
233 }
234
StartServer(const std::string & componentName)235 void StartServer(const std::string& componentName)
236 {
237 LOGI("StartServer, componentName = %{private}s", componentName.c_str());
238 g_inspector = std::make_unique<ConnectInspector>();
239 #ifdef PANDA_TARGET_ARM32
240 g_inspector->connectServer_ = std::make_unique<ConnectServer>(componentName,
241 std::bind(&OnMessage, std::placeholders::_1));
242
243 pthread_t tid;
244 if (pthread_create(&tid, nullptr, &HandleDebugManager,
245 static_cast<void*>(g_inspector->connectServer_.get())) != 0) {
246 LOGE("pthread_create fail!");
247 ResetService();
248 return;
249 }
250 #endif
251 }
252
StopServer(const std::string & componentName)253 void StopServer([[maybe_unused]] const std::string& componentName)
254 {
255 LOGI("StopServer, componentName = %{private}s", componentName.c_str());
256 ResetService();
257 }
258
StoreMessage(int32_t instanceId,const std::string & message)259 void StoreMessage(int32_t instanceId, const std::string& message)
260 {
261 std::lock_guard<std::mutex> lock(g_connectMutex);
262 if (g_inspector == nullptr) {
263 g_inspector = std::make_unique<ConnectInspector>();
264 }
265 if (g_inspector->infoBuffer_.count(instanceId) == 1) {
266 LOGE("The message with the current instance id has existed.");
267 return;
268 }
269 g_inspector->infoBuffer_[instanceId] = message;
270 }
271
RemoveMessage(int32_t instanceId)272 void RemoveMessage(int32_t instanceId)
273 {
274 std::lock_guard<std::mutex> lock(g_connectMutex);
275 if (g_inspector == nullptr) {
276 return;
277 }
278 if (g_inspector->infoBuffer_.count(instanceId) != 1) {
279 LOGE("The message with the current instance id does not exist.");
280 return;
281 }
282 g_inspector->infoBuffer_.erase(instanceId);
283 }
284
SendMessage(const std::string & message)285 void SendMessage(const std::string& message)
286 {
287 if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr && !g_inspector->waitingForDebugger_) {
288 g_inspector->connectServer_->SendMessage(message);
289 }
290 }
291
WaitForConnection()292 bool WaitForConnection()
293 {
294 if (g_inspector == nullptr) {
295 return true;
296 }
297 return g_inspector->waitingForDebugger_;
298 }
299
SetProfilerCallback(const std::function<void (bool)> & setArkUIStateProfilerStatus)300 void SetProfilerCallback(const std::function<void(bool)> &setArkUIStateProfilerStatus)
301 {
302 std::lock_guard<std::mutex> lock(g_connectMutex);
303 if (g_inspector == nullptr) {
304 g_inspector = std::make_unique<ConnectInspector>();
305 }
306 g_inspector->setArkUIStateProfilerStatus_ = setArkUIStateProfilerStatus;
307 }
308
SetRecordCallback(const std::function<void (void)> & startRecordFunc,const std::function<void (void)> & stopRecordFunc)309 void SetRecordCallback(const std::function<void(void)> &startRecordFunc,
310 const std::function<void(void)> &stopRecordFunc)
311 {
312 std::lock_guard<std::mutex> lock(g_connectMutex);
313 if (g_inspector == nullptr) {
314 g_inspector = std::make_unique<ConnectInspector>();
315 }
316 g_inspector->startRecord_ = startRecordFunc;
317 g_inspector->stopRecord_ = stopRecordFunc;
318 }
319
SetArkUICallback(const std::function<void (const char *)> & arkUICallback)320 void SetArkUICallback(const std::function<void(const char *)> &arkUICallback)
321 {
322 std::lock_guard<std::mutex> lock(g_connectMutex);
323 if (g_inspector == nullptr) {
324 g_inspector = std::make_unique<ConnectInspector>();
325 }
326 g_inspector->arkUICallback_ = arkUICallback;
327 }
328
SetWMSCallback(const std::function<void (const char *)> & wMSCallback)329 void SetWMSCallback(const std::function<void(const char *)> &wMSCallback)
330 {
331 std::lock_guard<std::mutex> lock(g_connectMutex);
332 if (g_inspector == nullptr) {
333 g_inspector = std::make_unique<ConnectInspector>();
334 }
335 g_inspector->wMSCallback_ = wMSCallback;
336 }
337
SetCangjieCallback(CJCallback & cangjieCallback)338 void SetCangjieCallback(CJCallback &cangjieCallback)
339 {
340 std::lock_guard<std::mutex> lock(g_connectMutex);
341 if (g_inspector == nullptr) {
342 g_inspector = std::make_unique<ConnectInspector>();
343 }
344 g_inspector->cangjieCallback_ = cangjieCallback;
345 }
346
ConnectRequest(const std::string & message)347 ConnectRequest::ConnectRequest(const std::string &message)
348 {
349 std::unique_ptr<PtJson> json = PtJson::Parse(message);
350 if (json == nullptr) {
351 LOGE("ConnectRequest, json == nullptr");
352 return;
353 }
354 if (!json->IsObject()) {
355 LOGE("ConnectRequest, json is not object");
356 json->ReleaseRoot();
357 return;
358 }
359
360 Result ret;
361 std::string wholeMethod;
362 ret = json->GetString("method", &wholeMethod);
363 if (ret != Result::SUCCESS || wholeMethod.empty()) {
364 LOGW("ConnectRequest, parse method error");
365 json->ReleaseRoot();
366 return;
367 }
368 std::string::size_type length = wholeMethod.length();
369 std::string::size_type indexPoint = wholeMethod.find_first_of('.', 0);
370 if (indexPoint == std::string::npos || indexPoint == 0 || indexPoint == length - 1) {
371 LOGW("ConnectRequest, method format error, msg = %{public}s", wholeMethod.c_str());
372 json->ReleaseRoot();
373 return;
374 }
375 domain_ = wholeMethod.substr(0, indexPoint);
376 isSuccess_ = true;
377 json->ReleaseRoot();
378 }
379 } // OHOS::ArkCompiler::Toolchain
380