• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 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 "inspector.h"
17 
18 #include <chrono>
19 #include <shared_mutex>
20 #if defined(OHOS_PLATFORM)
21 #include <syscall.h>
22 #endif
23 #include <thread>
24 #if defined(OHOS_PLATFORM)
25 #include <unistd.h>
26 #endif
27 #include <unordered_map>
28 
29 #include "common/log_wrapper.h"
30 #include "library_loader.h"
31 
32 #if defined(IOS_PLATFORM)
33 #include "tooling/debugger_service.h"
34 #endif
35 
36 namespace OHOS::ArkCompiler::Toolchain {
37 namespace {
38 enum DispatchStatus : int32_t {
39     UNKNOWN = 0,
40     DISPATCHING,
41     DISPATCHED
42 };
43 
44 using InitializeDebugger = void(*)(void*, const std::function<void(const void*, const std::string&)>&);
45 using UninitializeDebugger = void(*)(void*);
46 using WaitForDebugger = void(*)(void*);
47 using OnMessage = void(*)(void*, std::string&&);
48 using ProcessMessage = void(*)(void*);
49 using GetDispatchStatus = int32_t(*)(void*);
50 
51 OnMessage g_onMessage = nullptr;
52 InitializeDebugger g_initializeDebugger = nullptr;
53 UninitializeDebugger g_uninitializeDebugger = nullptr;
54 WaitForDebugger g_waitForDebugger = nullptr;
55 ProcessMessage g_processMessage = nullptr;
56 GetDispatchStatus g_getDispatchStatus = nullptr;
57 
58 std::atomic<bool> g_hasArkFuncsInited = false;
59 std::unordered_map<const void*, Inspector*> g_inspectors;
60 std::unordered_map<int, std::pair<void*, const DebuggerPostTask>> g_debuggerInfo;
61 std::shared_mutex g_mutex;
62 
63 #if !defined(IOS_PLATFORM)
64 thread_local void* g_handle = nullptr;
65 #endif
66 thread_local void* g_vm = nullptr;
67 
68 #if !defined(IOS_PLATFORM)
69 #if defined(WINDOWS_PLATFORM)
70 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.dll";
71 #elif defined(MAC_PLATFORM)
72 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.dylib";
73 #else
74 constexpr char ARK_DEBUGGER_SHARED_LIB[] = "libark_ecma_debugger.so";
75 #endif
76 #endif
77 
HandleClient(void * const server)78 void* HandleClient(void* const server)
79 {
80     LOGI("HandleClient");
81     if (server == nullptr) {
82         LOGE("HandleClient server nullptr");
83         return nullptr;
84     }
85 
86 #if defined(IOS_PLATFORM) || defined(MAC_PLATFORM)
87     pthread_setname_np("OS_DebugThread");
88 #else
89     pthread_setname_np(pthread_self(), "OS_DebugThread");
90 #endif
91 
92     static_cast<WsServer*>(server)->RunServer();
93     return nullptr;
94 }
95 
96 #if !defined(IOS_PLATFORM)
LoadArkDebuggerLibrary()97 bool LoadArkDebuggerLibrary()
98 {
99     if (g_handle != nullptr) {
100         LOGI("LoadArkDebuggerLibrary, handle has already loaded");
101         return true;
102     }
103     g_handle = Load(ARK_DEBUGGER_SHARED_LIB);
104     if (g_handle == nullptr) {
105         LOGE("LoadArkDebuggerLibrary, handle load failed");
106         return false;
107     }
108     return true;
109 }
110 
GetArkDynFunction(const char * symbol)111 void* GetArkDynFunction(const char* symbol)
112 {
113     return ResolveSymbol(g_handle, symbol);
114 }
115 #endif
116 
SendReply(const void * vm,const std::string & message)117 void SendReply(const void* vm, const std::string& message)
118 {
119     std::shared_lock<std::shared_mutex> lock(g_mutex);
120     auto iter = g_inspectors.find(vm);
121     if (iter != g_inspectors.end() && iter->second != nullptr &&
122         iter->second->websocketServer_ != nullptr) {
123         iter->second->websocketServer_->SendReply(message);
124     }
125 }
126 
ResetServiceLocked(void * vm,bool isCloseHandle)127 void ResetServiceLocked(void *vm, bool isCloseHandle)
128 {
129     auto iter = g_inspectors.find(vm);
130     if (iter != g_inspectors.end() && iter->second != nullptr &&
131         iter->second->websocketServer_ != nullptr) {
132         iter->second->websocketServer_->StopServer();
133         delete iter->second;
134         iter->second = nullptr;
135         g_inspectors.erase(iter);
136     }
137 #if !defined(IOS_PLATFORM)
138     if (g_handle != nullptr && isCloseHandle) {
139         CloseHandle(g_handle);
140         g_handle = nullptr;
141     }
142 #endif
143 }
144 
InitializeInspector(void * vm,const DebuggerPostTask & debuggerPostTask,const DebugInfo & debugInfo,int tidForSocketPair=0)145 bool InitializeInspector(
146     void* vm, const DebuggerPostTask& debuggerPostTask, const DebugInfo& debugInfo, int tidForSocketPair = 0)
147 {
148     std::unique_lock<std::shared_mutex> lock(g_mutex);
149     Inspector *newInspector = nullptr;
150     auto iter = g_inspectors.find(vm);
151     if (iter != g_inspectors.end()) {
152         newInspector = g_inspectors[vm];
153     } else {
154         newInspector = new Inspector();
155         if (!g_inspectors.emplace(vm, newInspector).second) {
156             delete newInspector;
157             return false;
158         }
159     }
160 
161     newInspector->tidForSocketPair_ = tidForSocketPair;
162     newInspector->tid_ = pthread_self();
163     newInspector->vm_ = vm;
164     newInspector->debuggerPostTask_ = debuggerPostTask;
165     newInspector->websocketServer_ = std::make_unique<WsServer>(debugInfo,
166         std::bind(&Inspector::OnMessage, newInspector, std::placeholders::_1));
167 
168     pthread_t tid;
169     if (pthread_create(&tid, nullptr, &HandleClient, static_cast<void *>(
170         newInspector->websocketServer_.get())) != 0) {
171         LOGE("Create inspector thread failed");
172         return false;
173     }
174     newInspector->websocketServer_->tid_ = tid;
175 
176     return true;
177 }
178 
InitializeArkFunctions()179 bool InitializeArkFunctions()
180 {
181     // no need to initialize again in case of multi-instance
182     if (g_hasArkFuncsInited) {
183         return true;
184     }
185 
186     std::unique_lock<std::shared_mutex> lock(g_mutex);
187     if (g_hasArkFuncsInited) {
188         return true;
189     }
190 #if !defined(IOS_PLATFORM)
191     g_initializeDebugger = reinterpret_cast<InitializeDebugger>(
192         GetArkDynFunction("InitializeDebugger"));
193     if (g_initializeDebugger == nullptr) {
194         ResetServiceLocked(g_vm, true);
195         return false;
196     }
197     g_uninitializeDebugger = reinterpret_cast<UninitializeDebugger>(
198         GetArkDynFunction("UninitializeDebugger"));
199     if (g_uninitializeDebugger == nullptr) {
200         ResetServiceLocked(g_vm, true);
201         return false;
202     }
203     g_waitForDebugger = reinterpret_cast<WaitForDebugger>(
204         GetArkDynFunction("WaitForDebugger"));
205     if (g_waitForDebugger == nullptr) {
206         ResetServiceLocked(g_vm, true);
207         return false;
208     }
209     g_onMessage = reinterpret_cast<OnMessage>(
210         GetArkDynFunction("OnMessage"));
211     if (g_onMessage == nullptr) {
212         ResetServiceLocked(g_vm, true);
213         return false;
214     }
215     g_getDispatchStatus = reinterpret_cast<GetDispatchStatus>(
216         GetArkDynFunction("GetDispatchStatus"));
217     if (g_getDispatchStatus == nullptr) {
218         ResetServiceLocked(g_vm, true);
219         return false;
220     }
221     g_processMessage = reinterpret_cast<ProcessMessage>(
222         GetArkDynFunction("ProcessMessage"));
223     if (g_processMessage == nullptr) {
224         ResetServiceLocked(g_vm, true);
225         return false;
226     }
227 #else
228     using namespace panda::ecmascript;
229     g_initializeDebugger = reinterpret_cast<InitializeDebugger>(&tooling::InitializeDebugger);
230     g_uninitializeDebugger = reinterpret_cast<UninitializeDebugger>(&tooling::UninitializeDebugger);
231     g_waitForDebugger = reinterpret_cast<WaitForDebugger>(&tooling::WaitForDebugger);
232     g_onMessage = reinterpret_cast<OnMessage>(&tooling::OnMessage);
233     g_getDispatchStatus = reinterpret_cast<GetDispatchStatus>(&tooling::GetDispatchStatus);
234     g_processMessage = reinterpret_cast<ProcessMessage>(&tooling::ProcessMessage);
235 #endif
236 
237     g_hasArkFuncsInited = true;
238     return true;
239 }
240 } // namespace
241 
OnMessage(std::string && msg)242 void Inspector::OnMessage(std::string&& msg)
243 {
244     g_onMessage(vm_, std::move(msg));
245 
246     // message will be processed soon if the debugger thread is in running or waiting status
247     if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
248         return;
249     }
250     std::this_thread::sleep_for(std::chrono::microseconds(DELAY_CHECK_DISPATCH_STATUS));
251     if (g_getDispatchStatus(vm_) != DispatchStatus::UNKNOWN) {
252         return;
253     }
254 
255     // the debugger thread maybe in idle status, so try to post a task to wake it up
256     if (debuggerPostTask_ != nullptr) {
257         if (tidForSocketPair_ == 0) {
258             debuggerPostTask_([tid = tid_, vm = vm_] {
259                 if (tid != pthread_self()) {
260                     LOGE("Task not in debugger thread");
261                     return;
262                 }
263                 g_processMessage(vm);
264             });
265         } else {
266 #if defined(OHOS_PLATFORM)
267             debuggerPostTask_([tid = tidForSocketPair_, vm = vm_] {
268                 if (tid != static_cast<pid_t>(syscall(SYS_gettid))) {
269                     LOGE("Task not in debugger thread for socketpair");
270                     return;
271                 }
272                 g_processMessage(vm);
273             });
274 #endif
275         }
276     } else {
277         LOGW("No debuggerPostTask provided");
278     }
279 }
280 
GetDebuggerPostTask(int tid)281 const DebuggerPostTask &GetDebuggerPostTask(int tid)
282 {
283     std::shared_lock<std::shared_mutex> lock(g_mutex);
284     if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
285         static DebuggerPostTask tempTask;
286         return tempTask;
287     }
288     return g_debuggerInfo[tid].second;
289 }
290 
GetEcmaVM(int tid)291 void *GetEcmaVM(int tid)
292 {
293     std::shared_lock<std::shared_mutex> lock(g_mutex);
294     if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
295         return nullptr;
296     }
297     return g_debuggerInfo[tid].first;
298 }
299 
InitializeDebuggerForSocketpair(void * vm)300 bool InitializeDebuggerForSocketpair(void* vm)
301 {
302 #if !defined(IOS_PLATFORM)
303     if (!LoadArkDebuggerLibrary()) {
304         return false;
305     }
306 #endif
307     if (!InitializeArkFunctions()) {
308         LOGE("Initialize ark functions failed");
309         return false;
310     }
311     g_initializeDebugger(vm, std::bind(&SendReply, vm, std::placeholders::_2));
312     return true;
313 }
314 
315 // for ohos platform.
StartDebugForSocketpair(int tid,int socketfd)316 bool StartDebugForSocketpair(int tid, int socketfd)
317 {
318     LOGI("StartDebugForSocketpair, tid = %{private}d, socketfd = %{private}d", tid, socketfd);
319     void* vm = GetEcmaVM(tid);
320     g_vm = vm;
321     if (!InitializeDebuggerForSocketpair(vm)) {
322         return false;
323     }
324     const DebuggerPostTask &debuggerPostTask = GetDebuggerPostTask(tid);
325     DebugInfo debugInfo = {socketfd};
326     if (!InitializeInspector(vm, debuggerPostTask, debugInfo, tid)) {
327         LOGE("Initialize inspector failed");
328         return false;
329     }
330 
331     return true;
332 }
333 
334 // for cross-platform, previewer and old process of StartDebugger.
StartDebug(const std::string & componentName,void * vm,bool isDebugMode,int32_t instanceId,const DebuggerPostTask & debuggerPostTask,int port)335 bool StartDebug(const std::string& componentName, void* vm, bool isDebugMode,
336     int32_t instanceId, const DebuggerPostTask& debuggerPostTask, int port)
337 {
338     LOGI("StartDebug, componentName = %{private}s, isDebugMode = %{private}d, instanceId = %{private}d",
339         componentName.c_str(), isDebugMode, instanceId);
340     g_vm = vm;
341 #if !defined(IOS_PLATFORM)
342     if (!LoadArkDebuggerLibrary()) {
343         return false;
344     }
345 #endif
346     if (!InitializeArkFunctions()) {
347         LOGE("Initialize ark functions failed");
348         return false;
349     }
350 
351     g_initializeDebugger(vm, std::bind(&SendReply, vm, std::placeholders::_2));
352 
353     int startDebugInOldProcess = -2; // start debug in old process.
354     DebugInfo debugInfo = {startDebugInOldProcess, componentName, instanceId, port};
355     if (!InitializeInspector(vm, debuggerPostTask, debugInfo)) {
356         LOGE("Initialize inspector failed");
357         return false;
358     }
359 
360     if (isDebugMode && port > 0) {
361         LOGI("Wait for debugger for previewer");
362         g_waitForDebugger(vm);
363     }
364     return true;
365 }
366 
WaitForDebugger(void * vm)367 void WaitForDebugger(void* vm)
368 {
369     LOGI("WaitForDebugger");
370     g_waitForDebugger(vm);
371 }
372 
StopDebug(const std::string & componentName)373 void StopDebug(const std::string& componentName)
374 {
375     LOGI("StopDebug start, componentName = %{private}s", componentName.c_str());
376     std::unique_lock<std::shared_mutex> lock(g_mutex);
377     auto iter = g_inspectors.find(g_vm);
378     if (iter == g_inspectors.end() || iter->second == nullptr) {
379         return;
380     }
381 
382     g_uninitializeDebugger(g_vm);
383     ResetServiceLocked(g_vm, true);
384     LOGI("StopDebug end");
385 }
386 
StopOldDebug(int tid,const std::string & componentName)387 void StopOldDebug(int tid, const std::string& componentName)
388 {
389     LOGI("StopDebug start, componentName = %{private}s, tid = %{private}d", componentName.c_str(), tid);
390     void* vm = GetEcmaVM(tid);
391     std::unique_lock<std::shared_mutex> lock(g_mutex);
392     auto iter = g_inspectors.find(vm);
393     if (iter == g_inspectors.end() || iter->second == nullptr) {
394         return;
395     }
396 
397     ResetServiceLocked(vm, false);
398     LOGI("StopDebug end");
399 }
400 
401 // for socketpair process.
StoreDebuggerInfo(int tid,void * vm,const DebuggerPostTask & debuggerPostTask)402 void StoreDebuggerInfo(int tid, void* vm, const DebuggerPostTask& debuggerPostTask)
403 {
404     std::unique_lock<std::shared_mutex> lock(g_mutex);
405     if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
406         g_debuggerInfo.emplace(tid, std::make_pair(vm, debuggerPostTask));
407     }
408 }
409 } // namespace OHOS::ArkCompiler::Toolchain
410