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 = void (*)(int);
48 using SendMessage = void (*)(const std::string&);
49 using SendLayoutMessage = void (*)(const std::string&);
50 using StopServer = void (*)(const std::string&);
51 using StoreMessage = void (*)(int32_t, const std::string&);
52 using StoreInspectorInfo = void (*)(const std::string&, const std::string&);
53 using SetProfilerCallback = void (*)(const std::function<void(bool)> &setArkUIStateProfilerStatus);
54 using SetSwitchCallBack = void (*)(const std::function<void(bool)> &setStatus,
55 const std::function<void(int32_t)> &createLayoutInfo, int32_t instanceId);
56 using SetConnectCallback = void (*)(const std::function<void(bool)>);
57 using RemoveMessage = void (*)(int32_t);
58 using WaitForConnection = bool (*)();
59 using SetRecordCallBack = void (*)(const std::function<void(void)> &startRecordFunc,
60 const std::function<void(void)> &stopRecordFunc);
61
62 std::mutex g_debuggerMutex;
63 std::mutex g_loadsoMutex;
64 std::mutex ConnectServerManager::instanceMutex_;
65 std::mutex ConnectServerManager::callbackMutex_;
66 std::unordered_map<int, std::pair<void*, const DebuggerPostTask>> g_debuggerInfo;
67
~ConnectServerManager()68 ConnectServerManager::~ConnectServerManager()
69 {
70 StopConnectServer();
71 }
72
Get()73 ConnectServerManager& ConnectServerManager::Get()
74 {
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(
110 AAFwkTag::JSRUNTIME, "null startServerForSocketPair");
111 return;
112 }
113 startServerForSocketPair(socketFd);
114
115 std::lock_guard<std::mutex> lock(callbackMutex_);
116 for (const auto &callback : connectServerCallbacks_) {
117 if (callback != nullptr) {
118 callback();
119 }
120 }
121 }
122
StopConnectServer(bool isCloseSo)123 void ConnectServerManager::StopConnectServer(bool isCloseSo)
124 {
125 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
126 if (handlerConnectServerSo_ == nullptr) {
127 TAG_LOGE(AAFwkTag::JSRUNTIME, "null handlerConnectServerSo_");
128 return;
129 }
130 auto stopServer = reinterpret_cast<StopServer>(dlsym(handlerConnectServerSo_, "StopServer"));
131 if (stopServer != nullptr) {
132 stopServer(bundleName_);
133 } else {
134 TAG_LOGE(AAFwkTag::JSRUNTIME, "null StopServer");
135 }
136 if (isCloseSo) {
137 dlclose(handlerConnectServerSo_);
138 handlerConnectServerSo_ = nullptr;
139 }
140 }
141
142
StoreInstanceMessage(int32_t tid,int32_t instanceId,const std::string & instanceName)143 bool ConnectServerManager::StoreInstanceMessage(int32_t tid, int32_t instanceId, const std::string& instanceName)
144 {
145 {
146 std::lock_guard<std::mutex> lock(mutex_);
147 auto result = instanceMap_.try_emplace(instanceId, std::make_pair(instanceName, tid));
148 if (!result.second) {
149 TAG_LOGW(AAFwkTag::JSRUNTIME, "Instance %{public}d added", instanceId);
150 return false;
151 }
152 }
153 return true;
154 }
155
StoreDebuggerInfo(int32_t tid,void * vm,const panda::JSNApi::DebugOption & debugOption,const DebuggerPostTask & debuggerPostTask,bool isDebugApp)156 void ConnectServerManager::StoreDebuggerInfo(int32_t tid, void* vm, const panda::JSNApi::DebugOption& debugOption,
157 const DebuggerPostTask& debuggerPostTask, bool isDebugApp)
158 {
159 std::lock_guard<std::mutex> lock(g_debuggerMutex);
160 if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
161 g_debuggerInfo.emplace(tid, std::make_pair(vm, debuggerPostTask));
162 }
163
164 if (!isConnected_) {
165 TAG_LOGW(AAFwkTag::JSRUNTIME, "not Connected");
166 return;
167 }
168
169 panda::JSNApi::StoreDebugInfo(tid, reinterpret_cast<panda::EcmaVM*>(vm), debugOption, debuggerPostTask, isDebugApp);
170 }
171
SendDebuggerInfo(bool needBreakPoint,bool isDebugApp)172 void ConnectServerManager::SendDebuggerInfo(bool needBreakPoint, bool isDebugApp)
173 {
174 ConnectServerManager::Get().SetConnectedCallback();
175 std::lock_guard<std::mutex> lock(mutex_);
176 for (const auto& instance : instanceMap_) {
177 auto instanceId = instance.first;
178 auto instanceName = instance.second.first;
179 auto tid = instance.second.second;
180
181 panda::EcmaVM* vm = reinterpret_cast<panda::EcmaVM*>(g_debuggerInfo[tid].first);
182 std::lock_guard<std::mutex> lock(g_debuggerMutex);
183 const auto &debuggerPostTask = g_debuggerInfo[tid].second;
184 if (!debuggerPostTask) {
185 continue;
186 }
187 ConnectServerManager::Get().SendInstanceMessage(tid, instanceId, instanceName);
188 panda::JSNApi::DebugOption debugOption = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? needBreakPoint : false};
189 panda::JSNApi::StoreDebugInfo(tid, vm, debugOption, debuggerPostTask, isDebugApp);
190 }
191 }
192
SetConnectedCallback()193 void ConnectServerManager::SetConnectedCallback()
194 {
195 LoadConnectServerDebuggerSo();
196
197 auto setConnectCallBack = reinterpret_cast<SetConnectCallback>(
198 dlsym(handlerConnectServerSo_, "SetConnectCallback"));
199 if (setConnectCallBack == nullptr) {
200 TAG_LOGE(AAFwkTag::JSRUNTIME, "null setConnectCallBack");
201 return;
202 }
203
204 setConnectCallBack([](bool isConnected) {
205 ConnectServerManager::Get().isConnected_ = isConnected;
206 });
207 }
208
SetSwitchCallback(int32_t instanceId)209 void ConnectServerManager::SetSwitchCallback(int32_t instanceId)
210 {
211 LoadConnectServerDebuggerSo();
212 auto setSwitchCallBack = reinterpret_cast<SetSwitchCallBack>(
213 dlsym(handlerConnectServerSo_, "SetSwitchCallBack"));
214 if (setSwitchCallBack == nullptr) {
215 TAG_LOGE(AAFwkTag::JSRUNTIME, "null setSwitchCallBack");
216 return;
217 }
218 setSwitchCallBack(
219 [this](bool status) {
220 if (setStatus_ != nullptr) {
221 setStatus_(status);
222 } else {
223 TAG_LOGE(AAFwkTag::JSRUNTIME, "null setStatus_");
224 }
225 },
226 [this](int32_t containerId) {
227 if (createLayoutInfo_ != nullptr) {
228 createLayoutInfo_(containerId);
229 } else {
230 TAG_LOGE(AAFwkTag::JSRUNTIME, "null createLayoutInfo_");
231 }
232 }, instanceId);
233 }
234
SetProfilerCallBack()235 void ConnectServerManager::SetProfilerCallBack()
236 {
237 LoadConnectServerDebuggerSo();
238 auto setProfilerCallback = reinterpret_cast<SetProfilerCallback>(
239 dlsym(handlerConnectServerSo_, "SetProfilerCallback"));
240 if (setProfilerCallback == nullptr) {
241 TAG_LOGE(AAFwkTag::JSRUNTIME,
242 "ConnectServerManager::AddInstance failed to find symbol 'setProfilerCallback'");
243 return;
244 }
245 setProfilerCallback([this](bool status) {
246 if (setArkUIStateProfilerStatus_ != nullptr) {
247 setArkUIStateProfilerStatus_(status);
248 } else {
249 TAG_LOGE(AAFwkTag::JSRUNTIME, "null etArkUIStateProfilerStatus_");
250 }
251 });
252 }
253
SendInstanceMessage(int32_t tid,int32_t instanceId,const std::string & instanceName)254 bool ConnectServerManager::SendInstanceMessage(int32_t tid, int32_t instanceId, const std::string& instanceName)
255 {
256 TAG_LOGI(AAFwkTag::JSRUNTIME, "called");
257 ConnectServerManager::Get().SetSwitchCallback(instanceId);
258 ConnectServerManager::Get().SetProfilerCallBack();
259 std::string message = GetInstanceMapMessage("addInstance", instanceId, instanceName, tid);
260 LoadConnectServerDebuggerSo();
261 auto storeMessage = reinterpret_cast<StoreMessage>(dlsym(handlerConnectServerSo_, "StoreMessage"));
262 if (storeMessage == nullptr) {
263 TAG_LOGE(AAFwkTag::JSRUNTIME, "null storeMessage");
264 return false;
265 }
266 storeMessage(instanceId, message);
267 return true;
268 }
269
270
AddInstance(int32_t tid,int32_t instanceId,const std::string & instanceName)271 bool ConnectServerManager::AddInstance(int32_t tid, int32_t instanceId, const std::string& instanceName)
272 {
273 {
274 std::lock_guard<std::mutex> lock(mutex_);
275 auto result = instanceMap_.try_emplace(instanceId, std::make_pair(instanceName, tid));
276 if (!result.second) {
277 TAG_LOGW(
278 AAFwkTag::JSRUNTIME, "Instance %{public}d added", instanceId);
279 return false;
280 }
281 }
282
283 if (!isConnected_) {
284 TAG_LOGW(AAFwkTag::JSRUNTIME, "not Connected");
285 return false;
286 }
287
288 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
289
290 ConnectServerManager::Get().SetSwitchCallback(instanceId);
291 ConnectServerManager::Get().SetProfilerCallBack();
292 LoadConnectServerDebuggerSo();
293 // Get the message including information of new instance, which will be send to IDE.
294 std::string message = GetInstanceMapMessage("addInstance", instanceId, instanceName, tid);
295
296 auto storeMessage = reinterpret_cast<StoreMessage>(dlsym(handlerConnectServerSo_, "StoreMessage"));
297 if (storeMessage == nullptr) {
298 TAG_LOGE(AAFwkTag::JSRUNTIME, "null StoreMessage");
299 return false;
300 }
301 storeMessage(instanceId, message);
302
303 // WaitForConnection() means the connection state of the connect server
304 auto sendMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
305 if (sendMessage == nullptr) {
306 TAG_LOGE(AAFwkTag::JSRUNTIME, "null SendMessage");
307 return false;
308 }
309 // if connected, message will be sent immediately.
310 sendMessage(message);
311 return true;
312 }
313
RemoveInstance(int32_t instanceId)314 void ConnectServerManager::RemoveInstance(int32_t instanceId)
315 {
316 TAG_LOGD(AAFwkTag::JSRUNTIME, "called");
317 std::string instanceName;
318 int32_t tid;
319
320 {
321 std::lock_guard<std::mutex> lock(mutex_);
322 auto it = instanceMap_.find(instanceId);
323 if (it == instanceMap_.end()) {
324 TAG_LOGW(AAFwkTag::JSRUNTIME, "Instance %{public}d not found", instanceId);
325 return;
326 }
327
328 instanceName = std::move(it->second.first);
329 tid = std::move(it->second.second);
330 instanceMap_.erase(it);
331 }
332
333 if (!isConnected_) {
334 TAG_LOGW(AAFwkTag::JSRUNTIME, "not Connected");
335 return;
336 }
337
338 LoadConnectServerDebuggerSo();
339 auto waitForConnection = reinterpret_cast<WaitForConnection>(dlsym(handlerConnectServerSo_, "WaitForConnection"));
340 if (waitForConnection == nullptr) {
341 TAG_LOGE(AAFwkTag::JSRUNTIME, "null WaitForConnection");
342 return;
343 }
344
345 // Get the message including information of deleted instance, which will be send to IDE.
346 std::string message = GetInstanceMapMessage("destroyInstance", instanceId, instanceName, tid);
347
348 auto removeMessage = reinterpret_cast<RemoveMessage>(dlsym(handlerConnectServerSo_, "RemoveMessage"));
349 if (removeMessage == nullptr) {
350 TAG_LOGE(AAFwkTag::JSRUNTIME, "null RemoveMessage");
351 return;
352 }
353 removeMessage(instanceId);
354
355 if (waitForConnection()) {
356 return;
357 }
358
359 auto sendMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
360 if (sendMessage == nullptr) {
361 TAG_LOGE(AAFwkTag::JSRUNTIME, "null sendMessage");
362 return;
363 }
364 sendMessage(message);
365 }
366
SendInspector(const std::string & jsonTreeStr,const std::string & jsonSnapshotStr)367 void ConnectServerManager::SendInspector(const std::string& jsonTreeStr, const std::string& jsonSnapshotStr)
368 {
369 TAG_LOGI(AAFwkTag::JSRUNTIME, "called");
370 auto sendLayoutMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendLayoutMessage"));
371 if (sendLayoutMessage == nullptr) {
372 TAG_LOGE(AAFwkTag::JSRUNTIME, "null sendLayoutMessage");
373 return;
374 }
375
376 sendLayoutMessage(jsonTreeStr);
377 sendLayoutMessage(jsonSnapshotStr);
378 auto storeInspectorInfo = reinterpret_cast<StoreInspectorInfo>(
379 dlsym(handlerConnectServerSo_, "StoreInspectorInfo"));
380 if (storeInspectorInfo == nullptr) {
381 TAG_LOGE(AAFwkTag::JSRUNTIME, "null StoreInspectorInfo");
382 return;
383 }
384 storeInspectorInfo(jsonTreeStr, jsonSnapshotStr);
385 }
386
SetLayoutInspectorCallback(const std::function<void (int32_t)> & createLayoutInfo,const std::function<void (bool)> & setStatus)387 void ConnectServerManager::SetLayoutInspectorCallback(
388 const std::function<void(int32_t)>& createLayoutInfo, const std::function<void(bool)>& setStatus)
389 {
390 createLayoutInfo_ = createLayoutInfo;
391 setStatus_ = setStatus;
392 }
393
GetLayoutInspectorCallback()394 std::function<void(int32_t)> ConnectServerManager::GetLayoutInspectorCallback()
395 {
396 return createLayoutInfo_;
397 }
398
SetStateProfilerCallback(const std::function<void (bool)> & setArkUIStateProfilerStatus)399 void ConnectServerManager::SetStateProfilerCallback(const std::function<void(bool)> &setArkUIStateProfilerStatus)
400 {
401 setArkUIStateProfilerStatus_ = setArkUIStateProfilerStatus;
402 }
403
SendArkUIStateProfilerMessage(const std::string & message)404 void ConnectServerManager::SendArkUIStateProfilerMessage(const std::string &message)
405 {
406 TAG_LOGI(AAFwkTag::JSRUNTIME, "called");
407 auto sendProfilerMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendProfilerMessage"));
408 if (sendProfilerMessage == nullptr) {
409 TAG_LOGE(AAFwkTag::JSRUNTIME, "null sendProfilerMessage");
410 return;
411 }
412
413 sendProfilerMessage(message);
414 }
415
GetDebuggerPostTask(int32_t tid)416 DebuggerPostTask ConnectServerManager::GetDebuggerPostTask(int32_t tid)
417 {
418 auto it = g_debuggerInfo.find(tid);
419 if (it == g_debuggerInfo.end()) {
420 TAG_LOGW(AAFwkTag::JSRUNTIME, "tid %{public}d not found", tid);
421 return nullptr;
422 }
423 return it->second.second;
424 }
425
SetRecordCallback(const std::function<void (void)> & startRecordFunc,const std::function<void (void)> & stopRecordFunc)426 bool ConnectServerManager::SetRecordCallback(const std::function<void(void)> &startRecordFunc,
427 const std::function<void(void)> &stopRecordFunc)
428 {
429 if (handlerConnectServerSo_ == nullptr) {
430 TAG_LOGE(AAFwkTag::JSRUNTIME, "No connected server");
431 return false;
432 }
433 auto setRecordCallback = reinterpret_cast<SetRecordCallBack>(dlsym(handlerConnectServerSo_, "SetRecordCallback"));
434 if (setRecordCallback == nullptr) {
435 TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to find SetRecordCallback");
436 return false;
437 }
438 setRecordCallback(startRecordFunc, stopRecordFunc);
439 return true;
440 }
441
SetRecordResults(const std::string & jsonArrayStr)442 void ConnectServerManager::SetRecordResults(const std::string &jsonArrayStr)
443 {
444 if (handlerConnectServerSo_ == nullptr) {
445 TAG_LOGE(AAFwkTag::JSRUNTIME, "No connected server");
446 return;
447 }
448 auto sendLayoutMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendLayoutMessage"));
449 if (sendLayoutMessage == nullptr) {
450 TAG_LOGE(AAFwkTag::JSRUNTIME, "Failed to find sendLayoutMessage");
451 return;
452 }
453 sendLayoutMessage(jsonArrayStr);
454 }
455
RegistConnectServerCallback(const ServerConnectCallback & connectServerCallback)456 void ConnectServerManager::RegistConnectServerCallback(const ServerConnectCallback &connectServerCallback)
457 {
458 if (connectServerCallback == nullptr) {
459 TAG_LOGE(AAFwkTag::JSRUNTIME, "null callback");
460 return;
461 }
462 std::lock_guard<std::mutex> lock(callbackMutex_);
463 for (const auto &callback : connectServerCallbacks_) {
464 if (callback == connectServerCallback) {
465 TAG_LOGE(AAFwkTag::JSRUNTIME, "callback exist");
466 return;
467 }
468 }
469 connectServerCallbacks_.emplace_back(connectServerCallback);
470 TAG_LOGD(AAFwkTag::JSRUNTIME, "regist succeed");
471 }
472
473 } // namespace OHOS::AbilityRuntime