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