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