• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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