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