1 /*
2 * Copyright (c) 2022 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_wrapper.h"
22
23 namespace OHOS::AbilityRuntime {
24 namespace {
GetInstanceMapMessage(const std::string & messageType,int32_t instanceId,const std::string & instanceName,bool isWorker)25 std::string GetInstanceMapMessage(
26 const std::string& messageType, int32_t instanceId, const std::string& instanceName, bool isWorker)
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 if (isWorker) {
37 message.append(std::to_string(instanceId));
38 } else {
39 message.append(std::to_string(gettid()));
40 }
41 message.append(",\"apiType\":\"");
42 message.append("stageMode\"");
43 message.append(",\"language\":\"");
44 message.append("ets\"");
45 message.append("}");
46 return message;
47 }
48 }
49
50 using StartServer = void (*)(const std::string&);
51 using StartServerForSocketPair = void (*)(int);
52 using SendMessage = void (*)(const std::string&);
53 using SendLayoutMessage = void (*)(const std::string&);
54 using StopServer = void (*)(const std::string&);
55 using StoreMessage = void (*)(int32_t, const std::string&);
56 using StoreInspectorInfo = void (*)(const std::string&, const std::string&);
57 using SetSwitchCallBack = void (*)(const std::function<void(bool)> &setStatus,
58 const std::function<void(int32_t)> &createLayoutInfo, int32_t instanceId);
59 using SetConnectCallback = void (*)(const std::function<void(bool)>);
60 using RemoveMessage = void (*)(int32_t);
61 using WaitForConnection = bool (*)();
62
63 std::mutex g_debuggerMutex;
64 std::mutex g_loadsoMutex;
65 std::mutex ConnectServerManager::instanceMutex_;
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 std::lock_guard<std::mutex> lock(instanceMutex_);
76 static ConnectServerManager connectServerManager;
77 return connectServerManager;
78 }
79
LoadConnectServerDebuggerSo()80 void ConnectServerManager::LoadConnectServerDebuggerSo()
81 {
82 std::lock_guard<std::mutex> lock(g_loadsoMutex);
83 if (handlerConnectServerSo_ == nullptr) {
84 handlerConnectServerSo_ = dlopen("libconnectserver_debugger.z.so", RTLD_LAZY);
85 if (handlerConnectServerSo_ == nullptr) {
86 HILOG_ERROR("ConnectServerManager::StartConnectServer failed to open register library");
87 return;
88 }
89 }
90 }
91
StartConnectServer(const std::string & bundleName,int socketFd,bool isLocalAbstract)92 void ConnectServerManager::StartConnectServer(const std::string& bundleName, int socketFd, bool isLocalAbstract)
93 {
94 HILOG_DEBUG("ConnectServerManager::StartConnectServer Start connect server");
95
96 LoadConnectServerDebuggerSo();
97 bundleName_ = bundleName;
98 if (isLocalAbstract) {
99 auto startServer = reinterpret_cast<StartServer>(dlsym(handlerConnectServerSo_, "StartServer"));
100 if (startServer == nullptr) {
101 HILOG_ERROR("ConnectServerManager::StartServer failed to find symbol 'StartServer'");
102 return;
103 }
104 startServer(bundleName_);
105 return;
106 }
107 auto startServerForSocketPair =
108 reinterpret_cast<StartServerForSocketPair>(dlsym(handlerConnectServerSo_, "StartServerForSocketPair"));
109 if (startServerForSocketPair == nullptr) {
110 HILOG_ERROR("ConnectServerManager::StartServerForSocketPair failed to find symbol 'StartServer'");
111 return;
112 }
113 startServerForSocketPair(socketFd);
114 }
115
StopConnectServer(bool isCloseSo)116 void ConnectServerManager::StopConnectServer(bool isCloseSo)
117 {
118 HILOG_DEBUG("ConnectServerManager::StopConnectServer Stop connect server");
119 if (handlerConnectServerSo_ == nullptr) {
120 HILOG_ERROR("ConnectServerManager::StopConnectServer handlerConnectServerSo_ is nullptr");
121 return;
122 }
123 auto stopServer = reinterpret_cast<StopServer>(dlsym(handlerConnectServerSo_, "StopServer"));
124 if (stopServer != nullptr) {
125 stopServer(bundleName_);
126 } else {
127 HILOG_ERROR("ConnectServerManager::StopConnectServer failed to find symbol 'StopServer'");
128 }
129 if (isCloseSo) {
130 dlclose(handlerConnectServerSo_);
131 handlerConnectServerSo_ = nullptr;
132 }
133 }
134
135
StoreInstanceMessage(int32_t instanceId,const std::string & instanceName,bool isWorker)136 bool ConnectServerManager::StoreInstanceMessage(int32_t instanceId, const std::string& instanceName, bool isWorker)
137 {
138 {
139 std::lock_guard<std::mutex> lock(mutex_);
140 auto result = instanceMap_.try_emplace(instanceId, std::make_pair(instanceName, isWorker));
141 if (!result.second) {
142 HILOG_WARN("ConnectServerManager::StoreInstanceMessage Instance %{public}d already added", instanceId);
143 return false;
144 }
145 }
146 return true;
147 }
148
StoreDebuggerInfo(int tid,void * vm,const panda::JSNApi::DebugOption & debugOption,const DebuggerPostTask & debuggerPostTask,bool isDebugApp)149 void ConnectServerManager::StoreDebuggerInfo(int tid, void* vm, const panda::JSNApi::DebugOption& debugOption,
150 const DebuggerPostTask& debuggerPostTask, bool isDebugApp)
151 {
152 std::lock_guard<std::mutex> lock(g_debuggerMutex);
153 if (g_debuggerInfo.find(tid) == g_debuggerInfo.end()) {
154 g_debuggerInfo.emplace(tid, std::make_pair(vm, debuggerPostTask));
155 }
156
157 if (!isConnected_) {
158 HILOG_WARN("ConnectServerManager::StoreDebuggerInfo not Connected");
159 return;
160 }
161
162 panda::JSNApi::StoreDebugInfo(tid, reinterpret_cast<panda::EcmaVM*>(vm), debugOption, debuggerPostTask, isDebugApp);
163 }
164
SendDebuggerInfo(bool needBreakPoint,bool isDebugApp)165 void ConnectServerManager::SendDebuggerInfo(bool needBreakPoint, bool isDebugApp)
166 {
167 ConnectServerManager::Get().SetConnectedCallback();
168 std::lock_guard<std::mutex> lock(mutex_);
169 for (const auto& instance : instanceMap_) {
170 auto instanceId = instance.first;
171 auto instanceName = instance.second.first;
172 auto isWorker = instance.second.second;
173
174 panda::EcmaVM* vm = reinterpret_cast<panda::EcmaVM*>(g_debuggerInfo[instanceId].first);
175 std::lock_guard<std::mutex> lock(g_debuggerMutex);
176 const auto &debuggerPoskTask = g_debuggerInfo[instanceId].second;
177 if (!debuggerPoskTask) {
178 continue;
179 }
180 ConnectServerManager::Get().SendInstanceMessage(instanceId, instanceName, isWorker);
181 auto storeDebugInfoTask = [needBreakPoint, isDebugApp, instanceId, vm, debuggerPoskTask, instanceName]() {
182 panda::JSNApi::DebugOption debugOption = {ARK_DEBUGGER_LIB_PATH, isDebugApp ? needBreakPoint : false};
183 panda::JSNApi::StoreDebugInfo(gettid(), vm, debugOption, debuggerPoskTask, isDebugApp);
184 };
185
186 debuggerPoskTask(storeDebugInfoTask);
187 }
188 }
189
SetConnectedCallback()190 void ConnectServerManager::SetConnectedCallback()
191 {
192 LoadConnectServerDebuggerSo();
193
194 auto setConnectCallBack = reinterpret_cast<SetConnectCallback>(
195 dlsym(handlerConnectServerSo_, "SetConnectCallback"));
196 if (setConnectCallBack == nullptr) {
197 HILOG_ERROR("ConnectServerManager::SetConnectedCallback failed to find symbol 'SetConnectCallBack'");
198 return;
199 }
200
201 setConnectCallBack([](bool isConnected) {
202 ConnectServerManager::Get().isConnected_ = isConnected;
203 });
204 }
205
SendInstanceMessage(int32_t instanceId,const std::string & instanceName,bool isWorker)206 bool ConnectServerManager::SendInstanceMessage(int32_t instanceId, const std::string& instanceName, bool isWorker)
207 {
208 HILOG_INFO("ConnectServerManager::SendInstanceMessage Add instance to connect server");
209 LoadConnectServerDebuggerSo();
210
211 auto setSwitchCallBack = reinterpret_cast<SetSwitchCallBack>(
212 dlsym(handlerConnectServerSo_, "SetSwitchCallBack"));
213 if (setSwitchCallBack == nullptr) {
214 HILOG_INFO("ConnectServerManager::SendInstanceMessage failed to find symbol 'setSwitchCallBack'");
215 return false;
216 }
217
218 auto storeMessage = reinterpret_cast<StoreMessage>(dlsym(handlerConnectServerSo_, "StoreMessage"));
219 if (storeMessage == nullptr) {
220 HILOG_ERROR("ConnectServerManager::SendInstanceMessage failed to find symbol 'StoreMessage'");
221 return false;
222 }
223
224 setSwitchCallBack([this](bool status) { setStatus_(status); },
225 [this](int32_t containerId) { createLayoutInfo_(containerId); }, instanceId);
226
227 std::string message = GetInstanceMapMessage("addInstance", instanceId, instanceName, isWorker);
228 storeMessage(instanceId, message);
229
230 return true;
231 }
232
233
AddInstance(int32_t instanceId,const std::string & instanceName,bool isWorker)234 bool ConnectServerManager::AddInstance(int32_t instanceId, const std::string& instanceName, bool isWorker)
235 {
236 {
237 std::lock_guard<std::mutex> lock(mutex_);
238 auto result = instanceMap_.try_emplace(instanceId, std::make_pair(instanceName, isWorker));
239 if (!result.second) {
240 HILOG_WARN("ConnectServerManager::AddInstance Instance %{public}d already added", instanceId);
241 return false;
242 }
243 }
244
245 if (!isConnected_) {
246 HILOG_WARN("ConnectServerManager::AddInstance not Connected");
247 return false;
248 }
249
250 HILOG_DEBUG("ConnectServerManager::AddInstance Add instance to connect server");
251 LoadConnectServerDebuggerSo();
252
253 auto setSwitchCallBack = reinterpret_cast<SetSwitchCallBack>(
254 dlsym(handlerConnectServerSo_, "SetSwitchCallBack"));
255 if (setSwitchCallBack == nullptr) {
256 HILOG_ERROR("ConnectServerManager::AddInstance failed to find symbol 'setSwitchCallBack'");
257 return false;
258 }
259 setSwitchCallBack([this](bool status) { setStatus_(status); },
260 [this](int32_t containerId) { createLayoutInfo_(containerId); }, instanceId);
261
262 // Get the message including information of new instance, which will be send to IDE.
263 std::string message = GetInstanceMapMessage("addInstance", instanceId, instanceName, isWorker);
264
265 auto storeMessage = reinterpret_cast<StoreMessage>(dlsym(handlerConnectServerSo_, "StoreMessage"));
266 if (storeMessage == nullptr) {
267 HILOG_ERROR("ConnectServerManager::AddInstance failed to find symbol 'StoreMessage'");
268 return false;
269 }
270 storeMessage(instanceId, message);
271
272 // WaitForConnection() means the connection state of the connect server
273 auto sendMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
274 if (sendMessage == nullptr) {
275 HILOG_ERROR("ConnectServerManager::AddInstance failed to find symbol 'SendMessage'");
276 return false;
277 }
278 // if connected, message will be sent immediately.
279 sendMessage(message);
280 return true;
281 }
282
RemoveInstance(int32_t instanceId)283 void ConnectServerManager::RemoveInstance(int32_t instanceId)
284 {
285 HILOG_DEBUG("ConnectServerManager::RemoveInstance Remove instance to connect server");
286 if (handlerConnectServerSo_ == nullptr) {
287 HILOG_ERROR("ConnectServerManager::RemoveInstance handlerConnectServerSo_ is nullptr");
288 return;
289 }
290
291 std::string instanceName;
292 bool isWorker;
293
294 {
295 std::lock_guard<std::mutex> lock(mutex_);
296 auto it = instanceMap_.find(instanceId);
297 if (it == instanceMap_.end()) {
298 HILOG_WARN("ConnectServerManager::RemoveInstance Instance %{public}d is not found", instanceId);
299 return;
300 }
301
302 instanceName = std::move(it->second.first);
303 isWorker = std::move(it->second.second);
304 instanceMap_.erase(it);
305 }
306
307 auto waitForConnection = reinterpret_cast<WaitForConnection>(dlsym(handlerConnectServerSo_, "WaitForConnection"));
308 if (waitForConnection == nullptr) {
309 HILOG_ERROR("ConnectServerManager::RemoveInstance failed to find symbol 'WaitForConnection'");
310 return;
311 }
312
313 // Get the message including information of deleted instance, which will be send to IDE.
314 std::string message = GetInstanceMapMessage("destroyInstance", instanceId, instanceName, isWorker);
315
316 auto removeMessage = reinterpret_cast<RemoveMessage>(dlsym(handlerConnectServerSo_, "RemoveMessage"));
317 if (removeMessage == nullptr) {
318 HILOG_ERROR("ConnectServerManager::RemoveInstance failed to find symbol 'RemoveMessage'");
319 return;
320 }
321 removeMessage(instanceId);
322
323 if (waitForConnection()) {
324 return;
325 }
326
327 auto sendMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
328 if (sendMessage == nullptr) {
329 HILOG_ERROR("ConnectServerManager::RemoveInstance failed to find symbol 'SendMessage'");
330 return;
331 }
332 sendMessage(message);
333 }
334
SendInspector(const std::string & jsonTreeStr,const std::string & jsonSnapshotStr)335 void ConnectServerManager::SendInspector(const std::string& jsonTreeStr, const std::string& jsonSnapshotStr)
336 {
337 HILOG_INFO("ConnectServerManager SendInspector Start");
338 auto sendLayoutMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendLayoutMessage"));
339 if (sendLayoutMessage == nullptr) {
340 HILOG_ERROR("ConnectServerManager::AddInstance failed to find symbol 'sendLayoutMessage'");
341 return;
342 }
343
344 sendLayoutMessage(jsonTreeStr);
345 sendLayoutMessage(jsonSnapshotStr);
346 auto storeInspectorInfo = reinterpret_cast<StoreInspectorInfo>(
347 dlsym(handlerConnectServerSo_, "StoreInspectorInfo"));
348 if (storeInspectorInfo == nullptr) {
349 HILOG_ERROR("ConnectServerManager::AddInstance failed to find symbol 'StoreInspectorInfo'");
350 return;
351 }
352 storeInspectorInfo(jsonTreeStr, jsonSnapshotStr);
353 }
354
SetLayoutInspectorCallback(const std::function<void (int32_t)> & createLayoutInfo,const std::function<void (bool)> & setStatus)355 void ConnectServerManager::SetLayoutInspectorCallback(
356 const std::function<void(int32_t)>& createLayoutInfo, const std::function<void(bool)>& setStatus)
357 {
358 createLayoutInfo_ = createLayoutInfo;
359 setStatus_ = setStatus;
360 }
361
GetLayoutInspectorCallback()362 std::function<void(int32_t)> ConnectServerManager::GetLayoutInspectorCallback()
363 {
364 return createLayoutInfo_;
365 }
366
367 } // namespace OHOS::AbilityRuntime