1/*
2 * Copyright (c) 2023-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 "connect_inspector.h"
17#include <mutex>
18#include "common/log_wrapper.h"
19namespace OHOS::ArkCompiler::Toolchain {
20std::mutex g_connectMutex;
21std::unique_ptr<ConnectInspector> g_inspector = nullptr;
22static constexpr char CONNECTED_MESSAGE[] = "connected";
23static constexpr char OPEN_MESSAGE[] = "layoutOpen";
24static constexpr char CLOSE_MESSAGE[] = "layoutClose";
25static constexpr char REQUEST_MESSAGE[] = "tree";
26static constexpr char STOPDEBUGGER_MESSAGE[] = "stopDebugger";
27static constexpr char OPEN_ARKUI_STATE_PROFILER[] = "ArkUIStateProfilerOpen";
28static constexpr char CLOSE_ARKUI_STATE_PROFILER[] = "ArkUIStateProfilerClose";
29static constexpr char START_RECORD_MESSAGE[] = "rsNodeStartRecord";
30static constexpr char STOP_RECORD_MESSAGE[] = "rsNodeStopRecord";
31std::function<void(bool)> g_setConnectCallBack;
32
33void* HandleDebugManager(void* const server)
34{
35    if (server == nullptr) {
36        LOGE("HandleDebugManager server nullptr");
37        return nullptr;
38    }
39#if defined(IOS_PLATFORM) || defined(MAC_PLATFORM)
40    pthread_setname_np("OS_DbgConThread");
41#else
42    pthread_setname_np(pthread_self(), "OS_DbgConThread");
43#endif
44
45    static_cast<ConnectServer*>(server)->RunServer();
46    return nullptr;
47}
48
49void OnConnectedMessage(const std::string& message)
50{
51    if (message.find(CONNECTED_MESSAGE, 0) != std::string::npos) {
52        g_inspector->waitingForDebugger_ = false;
53        if (g_setConnectCallBack != nullptr) {
54            g_setConnectCallBack(true);
55        }
56        for (auto& info : g_inspector->infoBuffer_) {
57            g_inspector->connectServer_->SendMessage(info.second);
58        }
59    }
60}
61
62void OnOpenMessage(const std::string& message)
63{
64    if (message.find(OPEN_MESSAGE, 0) != std::string::npos) {
65        if (g_inspector->setSwitchStatus_ != nullptr) {
66            LOGI("layoutOpen start");
67            g_inspector->setSwitchStatus_(true);
68        }
69    }
70}
71
72void OnInspectorRecordMessage(const std::string& message)
73{
74    if (message.find(START_RECORD_MESSAGE, 0) != std::string::npos) {
75        if (g_inspector->startRecord_ != nullptr && !g_inspector->isRecording_) {
76            LOGI("record start");
77            g_inspector->startRecord_();
78            g_inspector->isRecording_ = true;
79        }
80    }
81
82    if (message.find(STOP_RECORD_MESSAGE, 0) != std::string::npos) {
83        if (g_inspector->stopRecord_ != nullptr && g_inspector->isRecording_) {
84            LOGI("record stop");
85            g_inspector->stopRecord_();
86            g_inspector->isRecording_ = false;
87        }
88    }
89}
90
91void OnMessage(const std::string& message)
92{
93    std::lock_guard<std::mutex> lock(g_connectMutex);
94    if (message.empty()) {
95        LOGE("message is empty");
96        return;
97    }
98
99    LOGI("ConnectServer OnMessage: %{public}s", message.c_str());
100    if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr) {
101        g_inspector->ideMsgQueue_.push(message);
102        OnConnectedMessage(message);
103
104        OnOpenMessage(message);
105        if (message.find(CLOSE_MESSAGE, 0) != std::string::npos) {
106            if (g_setConnectCallBack != nullptr) {
107                g_setConnectCallBack(false);
108            }
109            if (g_inspector->setSwitchStatus_ != nullptr) {
110                LOGI("layoutClose start");
111                g_inspector->setSwitchStatus_(false);
112            }
113        }
114        if (message.find(OPEN_ARKUI_STATE_PROFILER, 0) != std::string::npos) {
115            if (g_inspector->setArkUIStateProfilerStatus_ != nullptr) {
116                LOGI("state profiler open");
117                g_inspector->setArkUIStateProfilerStatus_(true);
118            }
119        }
120        if (message.find(CLOSE_ARKUI_STATE_PROFILER, 0) != std::string::npos) {
121            if (g_inspector->setArkUIStateProfilerStatus_ != nullptr) {
122                LOGI("state profiler close");
123                g_inspector->setArkUIStateProfilerStatus_(false);
124            }
125        }
126        if (message.find(REQUEST_MESSAGE, 0) != std::string::npos) {
127            if (g_inspector->createLayoutInfo_ != nullptr) {
128                LOGI("tree start");
129                g_inspector->createLayoutInfo_(g_inspector->instanceId_);
130            }
131        }
132        if (message.find(STOPDEBUGGER_MESSAGE, 0) != std::string::npos) {
133            g_inspector->waitingForDebugger_ = true;
134            if (g_inspector->setDebugMode_ != nullptr) {
135                LOGI("stopDebugger start");
136                g_inspector->setDebugMode_();
137            }
138        }
139        OnInspectorRecordMessage(message);
140    }
141}
142
143void SetSwitchCallBack(const std::function<void(bool)>& setSwitchStatus,
144    const std::function<void(int32_t)>& createLayoutInfo, int32_t instanceId)
145{
146    std::lock_guard<std::mutex> lock(g_connectMutex);
147    if (g_inspector == nullptr) {
148        g_inspector = std::make_unique<ConnectInspector>();
149    }
150    g_inspector->setSwitchStatus_ = setSwitchStatus;
151    g_inspector->createLayoutInfo_ = createLayoutInfo;
152    g_inspector->instanceId_ = instanceId;
153}
154
155void SetConnectCallback(const std::function<void(bool)>& callback)
156{
157    g_setConnectCallBack = callback;
158}
159
160// stop debugger but the application continues to run
161void SetDebugModeCallBack(const std::function<void()>& setDebugMode)
162{
163    std::lock_guard<std::mutex> lock(g_connectMutex);
164    if (g_inspector != nullptr) {
165        g_inspector->setDebugMode_ = setDebugMode;
166    }
167}
168
169void ResetService()
170{
171    if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr) {
172        g_inspector->connectServer_->StopServer();
173        g_inspector->connectServer_.reset();
174    }
175}
176
177bool StartServerForSocketPair(int socketfd)
178{
179    LOGI("StartServerForSocketPair, socketfd = %{private}d", socketfd);
180    if (g_inspector == nullptr) {
181        g_inspector = std::make_unique<ConnectInspector>();
182    }
183    if (g_inspector->connectServer_ != nullptr) {
184        LOGW("ConnectServer is not nullptr!");
185        return true;
186    }
187    g_inspector->connectServer_ = std::make_unique<ConnectServer>(socketfd,
188        std::bind(&OnMessage, std::placeholders::_1));
189
190    pthread_t tid;
191    if (pthread_create(&tid, nullptr, &HandleDebugManager,
192        static_cast<void*>(g_inspector->connectServer_.get())) != 0) {
193        LOGE("pthread_create fail!");
194        ResetService();
195        return false;
196    }
197    return true;
198}
199
200void StartServer(const std::string& componentName)
201{
202    LOGI("StartServer, componentName = %{private}s", componentName.c_str());
203    g_inspector = std::make_unique<ConnectInspector>();
204#ifdef PANDA_TARGET_ARM32
205    g_inspector->connectServer_ = std::make_unique<ConnectServer>(componentName,
206        std::bind(&OnMessage, std::placeholders::_1));
207
208    pthread_t tid;
209    if (pthread_create(&tid, nullptr, &HandleDebugManager,
210        static_cast<void*>(g_inspector->connectServer_.get())) != 0) {
211        LOGE("pthread_create fail!");
212        ResetService();
213        return;
214    }
215#endif
216}
217
218void StopServer([[maybe_unused]] const std::string& componentName)
219{
220    LOGI("StopServer, componentName = %{private}s", componentName.c_str());
221    ResetService();
222}
223
224void StoreMessage(int32_t instanceId, const std::string& message)
225{
226    std::lock_guard<std::mutex> lock(g_connectMutex);
227    if (g_inspector == nullptr) {
228        g_inspector = std::make_unique<ConnectInspector>();
229    }
230    if (g_inspector->infoBuffer_.count(instanceId) == 1) {
231        LOGE("The message with the current instance id has existed.");
232        return;
233    }
234    g_inspector->infoBuffer_[instanceId] = message;
235}
236
237void StoreInspectorInfo(const std::string& jsonTreeStr, const std::string& jsonSnapshotStr)
238{
239    std::lock_guard<std::mutex> lock(g_connectMutex);
240    g_inspector->layoutInspectorInfo_.tree = jsonTreeStr;
241    g_inspector->layoutInspectorInfo_.snapShot = jsonSnapshotStr;
242}
243
244void RemoveMessage(int32_t instanceId)
245{
246    std::lock_guard<std::mutex> lock(g_connectMutex);
247    if (g_inspector == nullptr) {
248        return;
249    }
250    if (g_inspector->infoBuffer_.count(instanceId) != 1) {
251        LOGE("The message with the current instance id does not exist.");
252        return;
253    }
254    g_inspector->infoBuffer_.erase(instanceId);
255}
256
257void SendLayoutMessage(const std::string& message)
258{
259    LOGI("SendLayoutMessage start to send message");
260    if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr) {
261        g_inspector->connectServer_->SendMessage(message);
262    }
263}
264
265void SendMessage(const std::string& message)
266{
267    if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr && !g_inspector->waitingForDebugger_) {
268        g_inspector->connectServer_->SendMessage(message);
269    }
270}
271
272bool WaitForConnection()
273{
274    if (g_inspector == nullptr) {
275        return true;
276    }
277    return g_inspector->waitingForDebugger_;
278}
279
280// profiler methods
281
282void SendProfilerMessage(const std::string &message)
283{
284    LOGI("SendStateProfilerMessage start to send message");
285    if (g_inspector != nullptr && g_inspector->connectServer_ != nullptr) {
286        g_inspector->connectServer_->SendMessage(message);
287    }
288}
289
290void SetProfilerCallback(const std::function<void(bool)> &setArkUIStateProfilerStatus)
291{
292    std::lock_guard<std::mutex> lock(g_connectMutex);
293    if (g_inspector == nullptr) {
294        g_inspector = std::make_unique<ConnectInspector>();
295    }
296    g_inspector->setArkUIStateProfilerStatus_ = setArkUIStateProfilerStatus;
297}
298
299void SetRecordCallback(const std::function<void(void)> &startRecordFunc,
300    const std::function<void(void)> &stopRecordFunc)
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->startRecord_ = startRecordFunc;
307    g_inspector->stopRecord_ = stopRecordFunc;
308}
309} // OHOS::ArkCompiler::Toolchain
310