• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022-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_server_manager.h"
17 
18 #include <dlfcn.h>
19 #include <unistd.h>
20 
21 #include "hilog_tag_wrapper.h"
22 
23 namespace OHOS::AbilityRuntime {
24 namespace {
GetInstanceMapMessage(const std::string & messageType,int32_t instanceId,const std::string & instanceName,int32_t tid)25 std::string GetInstanceMapMessage(
26     const std::string& messageType, int32_t instanceId, const std::string& instanceName, int32_t tid)
27 {
28     std::string message;
29     message.append("{\"type\":\"");
30     message.append(messageType);
31     message.append("\",\"instanceId\":");
32     message.append(std::to_string(instanceId));
33     message.append(",\"name\":\"");
34     message.append(instanceName);
35     message.append("\",\"tid\":");
36     message.append(std::to_string(tid));
37     message.append(",\"apiType\":\"");
38     message.append("stageMode\"");
39     message.append(",\"language\":\"");
40     message.append("ets\"");
41     message.append("}");
42     return message;
43 }
44 }
45 
46 using StartServer = void (*)(const std::string&);
47 using StartServerForSocketPair = bool (*)(int);
48 using SendMessage = void (*)(const std::string&);
49 using StopServer = void (*)(const std::string&);
50 using StoreMessage = void (*)(int32_t, const std::string&);
51 using SetProfilerCallback = void (*)(const std::function<void(bool)> &setStateProfilerStatus);
52 using SetSwitchCallBack = void (*)(const std::function<void(int32_t)> &createLayoutInfo, int32_t instanceId);
53 using SetConnectCallback = void (*)(const std::function<void(bool)>);
54 using RemoveMessage = void (*)(int32_t);
55 using WaitForConnection = bool (*)();
56 using SetRecordCallBack = void (*)(const std::function<void(void)> &startRecordFunc,
57     const std::function<void(void)> &stopRecordFunc);
58 
59 std::mutex g_debuggerMutex;
60 std::mutex g_loadsoMutex;
61 std::mutex ConnectServerManager::instanceMutex_;
62 std::mutex ConnectServerManager::connectServerCallbackMutex_;
63 std::mutex ConnectServerManager::addInstanceCallbackMutex_;
64 std::mutex ConnectServerManager::sendInstanceMessageCallbackMutex_;
65 std::unordered_map<int, std::pair<void*, const DebuggerPostTask>> g_debuggerInfo;
66 
~ConnectServerManager()67 ConnectServerManager::~ConnectServerManager()
68 {
69     StopConnectServer();
70 }
71 
Get()72 ConnectServerManager& ConnectServerManager::Get()
73 {
74     std::lock_guard<std::mutex> lock(instanceMutex_);
75     static ConnectServerManager connectServerManager;
76     return connectServerManager;
77 }
78 
LoadConnectServerDebuggerSo()79 void ConnectServerManager::LoadConnectServerDebuggerSo()
80 {
81     std::lock_guard<std::mutex> lock(g_loadsoMutex);
82     if (handlerConnectServerSo_ == nullptr) {
83         handlerConnectServerSo_ = dlopen("libark_connect_inspector.z.so", RTLD_LAZY);
84         if (handlerConnectServerSo_ == nullptr) {
85             TAG_LOGE(AAFwkTag::JSRUNTIME, "null handlerConnectServerSo_");
86             return;
87         }
88     }
89 }
90 
StartConnectServer(const std::string & bundleName,int socketFd,bool isLocalAbstract)91 void ConnectServerManager::StartConnectServer(const std::string& bundleName, int socketFd, bool isLocalAbstract)
92 {
93     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
94 
95     LoadConnectServerDebuggerSo();
96     bundleName_ = bundleName;
97     if (isLocalAbstract) {
98         auto startServer = reinterpret_cast<StartServer>(dlsym(handlerConnectServerSo_, "StartServer"));
99         if (startServer == nullptr) {
100             TAG_LOGE(AAFwkTag::JSRUNTIME, "null startServer");
101             return;
102         }
103         startServer(bundleName_);
104         return;
105     }
106     auto startServerForSocketPair =
107         reinterpret_cast<StartServerForSocketPair>(dlsym(handlerConnectServerSo_, "StartServerForSocketPair"));
108     if (startServerForSocketPair == nullptr) {
109         TAG_LOGE(AAFwkTag::JSRUNTIME, "null startServerForSocketPair");
110         return;
111     }
112     startServerForSocketPair(socketFd);
113 
114     std::lock_guard<std::mutex> lock(connectServerCallbackMutex_);
115     for (const auto &callback : connectServerCallbacks_) {
116         if (callback != nullptr) {
117             callback();
118         }
119     }
120 }
121 
StopConnectServer(bool isCloseSo)122 void ConnectServerManager::StopConnectServer(bool isCloseSo)
123 {
124     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
125     if (handlerConnectServerSo_ == nullptr) {
126         TAG_LOGE(AAFwkTag::JSRUNTIME, "null handlerConnectServerSo_");
127         return;
128     }
129     auto stopServer = reinterpret_cast<StopServer>(dlsym(handlerConnectServerSo_, "StopServer"));
130     if (stopServer != nullptr) {
131         stopServer(bundleName_);
132     } else {
133         TAG_LOGE(AAFwkTag::JSRUNTIME, "null StopServer");
134     }
135     if (isCloseSo) {
136         dlclose(handlerConnectServerSo_);
137         handlerConnectServerSo_ = nullptr;
138     }
139 }
140 
StoreInstanceMessage(int32_t tid,int32_t instanceId,const std::string & instanceName)141 bool ConnectServerManager::StoreInstanceMessage(int32_t tid, int32_t instanceId, const std::string& instanceName)
142 {
143     {
144         std::lock_guard<std::mutex> lock(mutex_);
145         auto result = instanceMap_.try_emplace(instanceId, std::make_pair(instanceName, tid));
146         if (!result.second) {
147             TAG_LOGW(AAFwkTag::JSRUNTIME, "Instance %{public}d added", instanceId);
148             return false;
149         }
150     }
151     return true;
152 }
153 
StoreDebuggerInfo(int32_t tid,void * vm,const panda::JSNApi::DebugOption & debugOption,const DebuggerPostTask & debuggerPostTask,bool isDebugApp)154 void ConnectServerManager::StoreDebuggerInfo(int32_t tid, void* vm, const panda::JSNApi::DebugOption& debugOption,
155     const DebuggerPostTask& debuggerPostTask, bool isDebugApp)
156 {
157     std::lock_guard<std::mutex> lock(g_debuggerMutex);
158     if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
159         g_debuggerInfo.emplace(tid, std::make_pair(vm, debuggerPostTask));
160     }
161 
162     if (!isConnected_) {
163         TAG_LOGW(AAFwkTag::JSRUNTIME, "not Connected");
164         return;
165     }
166 
167     panda::JSNApi::StoreDebugInfo(tid, reinterpret_cast<panda::EcmaVM*>(vm), debugOption, debuggerPostTask, isDebugApp);
168 }
169 
SendDebuggerInfo(bool needBreakPoint,bool isDebugApp)170 void ConnectServerManager::SendDebuggerInfo(bool needBreakPoint, bool isDebugApp)
171 {
172     ConnectServerManager::Get().SetConnectedCallback();
173     std::lock_guard<std::mutex> lock(mutex_);
174     for (const auto& instance : instanceMap_) {
175         auto instanceId = instance.first;
176         auto instanceName = instance.second.first;
177         auto tid = instance.second.second;
178 
179         panda::EcmaVM* vm = reinterpret_cast<panda::EcmaVM*>(g_debuggerInfo[tid].first);
180         std::lock_guard<std::mutex> lock(g_debuggerMutex);
181         const auto &debuggerPostTask = g_debuggerInfo[tid].second;
182         if (!debuggerPostTask) {
183             continue;
184         }
185         ConnectServerManager::Get().SendInstanceMessage(tid, instanceId, instanceName);
186         panda::JSNApi::DebugOption debugOption = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? needBreakPoint : false};
187         panda::JSNApi::StoreDebugInfo(tid, vm, debugOption, debuggerPostTask, isDebugApp);
188     }
189 }
190 
SetConnectedCallback()191 void ConnectServerManager::SetConnectedCallback()
192 {
193     LoadConnectServerDebuggerSo();
194 
195     auto setConnectCallBack = reinterpret_cast<SetConnectCallback>(
196         dlsym(handlerConnectServerSo_, "SetConnectCallback"));
197     if (setConnectCallBack == nullptr) {
198         TAG_LOGE(AAFwkTag::JSRUNTIME, "null setConnectCallBack");
199         return;
200     }
201 
202     setConnectCallBack([](bool isConnected) {
203         ConnectServerManager::Get().isConnected_ = isConnected;
204     });
205 }
206 
SetSwitchCallback(const std::function<void (int32_t)> & createLayoutInfo,int32_t instanceId)207 void ConnectServerManager::SetSwitchCallback(const std::function<void(int32_t)> &createLayoutInfo, int32_t instanceId)
208 {
209     LoadConnectServerDebuggerSo();
210     auto setSwitchCallBack = reinterpret_cast<SetSwitchCallBack>(
211         dlsym(handlerConnectServerSo_, "SetSwitchCallBack"));
212     if (setSwitchCallBack == nullptr) {
213         TAG_LOGE(AAFwkTag::JSRUNTIME, "null setSwitchCallBack");
214         return;
215     }
216     setSwitchCallBack(createLayoutInfo, instanceId);
217 }
218 
SetProfilerCallBack(const std::function<void (bool)> & setStateProfilerStatus)219 void ConnectServerManager::SetProfilerCallBack(const std::function<void(bool)> &setStateProfilerStatus)
220 {
221     LoadConnectServerDebuggerSo();
222     auto setProfilerCallback = reinterpret_cast<SetProfilerCallback>(
223         dlsym(handlerConnectServerSo_, "SetProfilerCallback"));
224     if (setProfilerCallback == nullptr) {
225         TAG_LOGE(AAFwkTag::JSRUNTIME, "null setProfilerCallback");
226         return;
227     }
228     setProfilerCallback(setStateProfilerStatus);
229 }
230 
SendInstanceMessage(int32_t tid,int32_t instanceId,const std::string & instanceName)231 bool ConnectServerManager::SendInstanceMessage(int32_t tid, int32_t instanceId, const std::string& instanceName)
232 {
233     TAG_LOGI(AAFwkTag::JSRUNTIME, "called");
234     ConnectServerManager::Get().SendInstanceMessageCallback(instanceId);
235     std::string message = GetInstanceMapMessage("addInstance", instanceId, instanceName, tid);
236     LoadConnectServerDebuggerSo();
237     auto storeMessage = reinterpret_cast<StoreMessage>(dlsym(handlerConnectServerSo_, "StoreMessage"));
238     if (storeMessage == nullptr) {
239         TAG_LOGE(AAFwkTag::JSRUNTIME, "null storeMessage");
240         return false;
241     }
242     storeMessage(instanceId, message);
243     return true;
244 }
245 
AddInstance(int32_t tid,int32_t instanceId,const std::string & instanceName)246 bool ConnectServerManager::AddInstance(int32_t tid, int32_t instanceId, const std::string& instanceName)
247 {
248     {
249         std::lock_guard<std::mutex> lock(mutex_);
250         auto result = instanceMap_.try_emplace(instanceId, std::make_pair(instanceName, tid));
251         if (!result.second) {
252             TAG_LOGW(AAFwkTag::JSRUNTIME, "instance %{public}d added", instanceId);
253             return false;
254         }
255     }
256 
257     if (!isConnected_) {
258         TAG_LOGW(AAFwkTag::JSRUNTIME, "not Connected");
259         return false;
260     }
261 
262     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
263 
264     ConnectServerManager::Get().AddInstanceCallback(instanceId);
265     LoadConnectServerDebuggerSo();
266     // Get the message including information of new instance, which will be send to IDE.
267     std::string message = GetInstanceMapMessage("addInstance", instanceId, instanceName, tid);
268 
269     auto storeMessage = reinterpret_cast<StoreMessage>(dlsym(handlerConnectServerSo_, "StoreMessage"));
270     if (storeMessage == nullptr) {
271         TAG_LOGE(AAFwkTag::JSRUNTIME, "null StoreMessage");
272         return false;
273     }
274     storeMessage(instanceId, message);
275 
276     // WaitForConnection() means the connection state of the connect server
277     auto sendMessage =
278         reinterpret_cast<OHOS::AbilityRuntime::SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
279     if (sendMessage == nullptr) {
280         TAG_LOGE(AAFwkTag::JSRUNTIME, "null SendMessage");
281         return false;
282     }
283     // if connected, message will be sent immediately.
284     sendMessage(message);
285     return true;
286 }
287 
RemoveInstance(int32_t instanceId)288 void ConnectServerManager::RemoveInstance(int32_t instanceId)
289 {
290     TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
291     std::string instanceName;
292     int32_t tid;
293 
294     {
295         std::lock_guard<std::mutex> lock(mutex_);
296         auto it = instanceMap_.find(instanceId);
297         if (it == instanceMap_.end()) {
298             TAG_LOGW(AAFwkTag::JSRUNTIME, "Instance %{public}d not found", instanceId);
299             return;
300         }
301 
302         instanceName = std::move(it->second.first);
303         tid = std::move(it->second.second);
304         instanceMap_.erase(it);
305     }
306 
307     if (!isConnected_) {
308         TAG_LOGW(AAFwkTag::JSRUNTIME, "not Connected");
309         return;
310     }
311 
312     LoadConnectServerDebuggerSo();
313     auto waitForConnection = reinterpret_cast<WaitForConnection>(dlsym(handlerConnectServerSo_, "WaitForConnection"));
314     if (waitForConnection == nullptr) {
315         TAG_LOGE(AAFwkTag::JSRUNTIME, "null WaitForConnection");
316         return;
317     }
318 
319     // Get the message including information of deleted instance, which will be send to IDE.
320     std::string message = GetInstanceMapMessage("destroyInstance", instanceId, instanceName, tid);
321 
322     auto removeMessage = reinterpret_cast<RemoveMessage>(dlsym(handlerConnectServerSo_, "RemoveMessage"));
323     if (removeMessage == nullptr) {
324         TAG_LOGE(AAFwkTag::JSRUNTIME, "null RemoveMessage");
325         return;
326     }
327     removeMessage(instanceId);
328 
329     if (waitForConnection()) {
330         return;
331     }
332 
333     auto sendMessage =
334         reinterpret_cast<OHOS::AbilityRuntime::SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
335     if (sendMessage == nullptr) {
336         TAG_LOGE(AAFwkTag::JSRUNTIME, "null sendMessage");
337         return;
338     }
339     sendMessage(message);
340 }
341 
SendInspector(const std::string & jsonTreeStr,const std::string & jsonSnapshotStr)342 void ConnectServerManager::SendInspector(const std::string& jsonTreeStr, const std::string& jsonSnapshotStr)
343 {
344     TAG_LOGI(AAFwkTag::JSRUNTIME, "called");
345     auto sendMessage =
346         reinterpret_cast<OHOS::AbilityRuntime::SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
347     if (sendMessage == nullptr) {
348         TAG_LOGE(AAFwkTag::JSRUNTIME, "null sendMessage");
349         return;
350     }
351     sendMessage(jsonTreeStr);
352     sendMessage(jsonSnapshotStr);
353 }
354 
SendMessage(const std::string & message)355 void ConnectServerManager::SendMessage(const std::string &message)
356 {
357     TAG_LOGI(AAFwkTag::JSRUNTIME, "called");
358     auto sendMessage =
359         reinterpret_cast<OHOS::AbilityRuntime::SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
360     if (sendMessage == nullptr) {
361         TAG_LOGE(AAFwkTag::JSRUNTIME, "null sendMessage");
362         return;
363     }
364 
365     sendMessage(message);
366 }
367 
GetDebuggerPostTask(int32_t tid)368 DebuggerPostTask ConnectServerManager::GetDebuggerPostTask(int32_t tid)
369 {
370     auto it = g_debuggerInfo.find(tid);
371     if (it == g_debuggerInfo.end()) {
372         TAG_LOGW(AAFwkTag::JSRUNTIME, "tid %{public}d not found", tid);
373         return nullptr;
374     }
375     return it->second.second;
376 }
377 
SetRecordCallback(const std::function<void (void)> & startRecordFunc,const std::function<void (void)> & stopRecordFunc)378 bool ConnectServerManager::SetRecordCallback(const std::function<void(void)> &startRecordFunc,
379     const std::function<void(void)> &stopRecordFunc)
380 {
381     if (handlerConnectServerSo_ == nullptr) {
382         TAG_LOGE(AAFwkTag::JSRUNTIME, "No connected server");
383         return false;
384     }
385     auto setRecordCallback = reinterpret_cast<SetRecordCallBack>(dlsym(handlerConnectServerSo_, "SetRecordCallback"));
386     if (setRecordCallback == nullptr) {
387         TAG_LOGE(AAFwkTag::JSRUNTIME, "null setRecordCallback");
388         return false;
389     }
390     setRecordCallback(startRecordFunc, stopRecordFunc);
391     return true;
392 }
393 
SetRecordResults(const std::string & jsonArrayStr)394 void ConnectServerManager::SetRecordResults(const std::string &jsonArrayStr)
395 {
396     if (handlerConnectServerSo_ == nullptr) {
397         TAG_LOGE(AAFwkTag::JSRUNTIME, "No connected server");
398         return;
399     }
400     auto sendMessage =
401         reinterpret_cast<OHOS::AbilityRuntime::SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
402     if (sendMessage == nullptr) {
403         TAG_LOGE(AAFwkTag::JSRUNTIME, "null sendMessage");
404         return;
405     }
406     sendMessage(jsonArrayStr);
407 }
408 
RegisterConnectServerCallback(const ServerConnectCallback & connectServerCallback)409 void ConnectServerManager::RegisterConnectServerCallback(const ServerConnectCallback &connectServerCallback)
410 {
411     if (connectServerCallback == nullptr) {
412         TAG_LOGE(AAFwkTag::JSRUNTIME, "null callback");
413         return;
414     }
415     std::lock_guard<std::mutex> lock(connectServerCallbackMutex_);
416     for (const auto &callback : connectServerCallbacks_) {
417         if (callback == connectServerCallback) {
418             TAG_LOGE(AAFwkTag::JSRUNTIME, "callback exist");
419             return;
420         }
421     }
422     connectServerCallbacks_.emplace_back(connectServerCallback);
423     TAG_LOGD(AAFwkTag::JSRUNTIME, "register connectServerCallback succeed");
424 }
425 
RegisterSendInstanceMessageCallback(const SendInstanceMessageCallBack & sendInstanceMessageCallback)426 void ConnectServerManager::RegisterSendInstanceMessageCallback(
427     const SendInstanceMessageCallBack &sendInstanceMessageCallback)
428 {
429     if (sendInstanceMessageCallback == nullptr) {
430         TAG_LOGE(AAFwkTag::JSRUNTIME, "null callback");
431         return;
432     }
433     std::lock_guard<std::mutex> lock(sendInstanceMessageCallbackMutex_);
434     for (const auto &callback : sendInstanceMessageCallbacks_) {
435         if (callback == sendInstanceMessageCallback) {
436             TAG_LOGE(AAFwkTag::JSRUNTIME, "callback exist");
437             return;
438         }
439     }
440     sendInstanceMessageCallbacks_.emplace_back(sendInstanceMessageCallback);
441     TAG_LOGD(AAFwkTag::JSRUNTIME, "register sendInstanceMessageCallback succeed");
442 }
443 
SendInstanceMessageCallback(const int32_t instanceId)444 void ConnectServerManager::SendInstanceMessageCallback(const int32_t instanceId)
445 {
446     std::lock_guard<std::mutex> lock(sendInstanceMessageCallbackMutex_);
447     for (const auto &callback : sendInstanceMessageCallbacks_) {
448         if (callback != nullptr) {
449             callback(instanceId);
450         }
451     }
452 }
453 
RegisterAddInstanceCallback(const AddInstanceCallBack & addInstanceCallback)454 void ConnectServerManager::RegisterAddInstanceCallback(const AddInstanceCallBack &addInstanceCallback)
455 {
456     if (addInstanceCallback == nullptr) {
457         TAG_LOGE(AAFwkTag::JSRUNTIME, "null callback");
458         return;
459     }
460     std::lock_guard<std::mutex> lock(addInstanceCallbackMutex_);
461     for (const auto &callback : addInstanceCallbacks_) {
462         if (callback == addInstanceCallback) {
463             TAG_LOGE(AAFwkTag::JSRUNTIME, "callback exist");
464             return;
465         }
466     }
467     addInstanceCallbacks_.emplace_back(addInstanceCallback);
468     TAG_LOGD(AAFwkTag::JSRUNTIME, "register addInstanceCallback succeed");
469 }
470 
AddInstanceCallback(const int32_t instanceId)471 void ConnectServerManager::AddInstanceCallback(const int32_t instanceId)
472 {
473     std::lock_guard<std::mutex> lock(addInstanceCallbackMutex_);
474     for (const auto &callback : addInstanceCallbacks_) {
475         if (callback != nullptr) {
476             callback(instanceId);
477         }
478     }
479 }
480 } // namespace OHOS::AbilityRuntime