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