• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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