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