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