1 /*
2 * Copyright (c) 2021 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 "core/common/connect_server_manager.h"
17
18 #include <dlfcn.h>
19 #include <string>
20 #include <unistd.h>
21
22 #include "base/json/json_util.h"
23 #include "base/log/log.h"
24 #include "base/utils/utils.h"
25 #include "core/common/ace_application_info.h"
26 #include "core/common/ace_engine.h"
27 #include "core/common/ace_page.h"
28 #include "core/common/container.h"
29 #include "core/common/layout_inspector.h"
30 #include "core/event/ace_event_handler.h"
31
32 #if defined(IOS_PLATFORM)
33 #include "inspector/connect_inspector.h"
34 #include <sys/sysctl.h>
35 #endif
36
37 namespace OHOS::Ace {
38
39 namespace {
40
41 using StartServer = bool (*)(const std::string& packageName);
42 using StartServerForSocketPair = void (*)(int32_t);
43 using SendMessage = void (*)(const std::string& message);
44 using SendLayoutMessage = void (*)(const std::string& message);
45 using StopServer = void (*)(const std::string& packageName);
46 using StoreMessage = void (*)(int32_t instanceId, const std::string& message);
47 using StoreInspectorInfo = void (*)(const std::string& jsonTreeStr, const std::string& jsonSnapshotStr);
48 using RemoveMessage = void (*)(int32_t instanceId);
49 using WaitForConnection = bool (*)();
50 using SetSwitchCallBack = void (*)(const std::function<void(bool)>& setStatus,
51 const std::function<void(int32_t)>& createLayoutInfo, int32_t instanceId);
52 using SetDebugModeCallBack = void (*)(const std::function<void()>& setDebugMode);
53
54 SendMessage g_sendMessage = nullptr;
55 SendLayoutMessage g_sendLayoutMessage = nullptr;
56 RemoveMessage g_removeMessage = nullptr;
57 StoreInspectorInfo g_storeInspectorInfo = nullptr;
58 StoreMessage g_storeMessage = nullptr;
59 SetSwitchCallBack g_setSwitchCallBack = nullptr;
60 SetDebugModeCallBack g_setDebugModeCallBack = nullptr;
61 WaitForConnection g_waitForConnection = nullptr;
62
63
64 } // namespace
65
ConnectServerManager()66 ConnectServerManager::ConnectServerManager(): handlerConnectServerSo_(nullptr)
67 {
68 isDebugVersion_ = AceApplicationInfo::GetInstance().IsDebugVersion();
69 if (!isDebugVersion_) {
70 return;
71 }
72 packageName_ = AceApplicationInfo::GetInstance().GetPackageName();
73 InitConnectServer();
74 }
75
~ConnectServerManager()76 ConnectServerManager::~ConnectServerManager()
77 {
78 if (!isDebugVersion_) {
79 return;
80 }
81 StopConnectServer();
82 CloseConnectServerSo();
83 }
84
CheckDebugVersion()85 bool ConnectServerManager::CheckDebugVersion()
86 {
87 #if !defined(IOS_PLATFORM)
88 if (!isDebugVersion_ || handlerConnectServerSo_ == nullptr) {
89 return false;
90 }
91 #else
92 if (!isDebugVersion_) {
93 return false;
94 }
95 #endif
96 return true;
97 }
98
Get()99 ConnectServerManager& ConnectServerManager::Get()
100 {
101 static ConnectServerManager connectServerManager;
102 return connectServerManager;
103 }
104
InitFunc()105 bool ConnectServerManager::InitFunc()
106 {
107 #if !defined(IOS_PLATFORM)
108 g_sendMessage = reinterpret_cast<SendMessage>(dlsym(handlerConnectServerSo_, "SendMessage"));
109 g_storeMessage = reinterpret_cast<StoreMessage>(dlsym(handlerConnectServerSo_, "StoreMessage"));
110 g_removeMessage = reinterpret_cast<RemoveMessage>(dlsym(handlerConnectServerSo_, "RemoveMessage"));
111 g_setSwitchCallBack = reinterpret_cast<SetSwitchCallBack>(dlsym(handlerConnectServerSo_, "SetSwitchCallBack"));
112 g_setDebugModeCallBack =
113 reinterpret_cast<SetDebugModeCallBack>(dlsym(handlerConnectServerSo_, "SetDebugModeCallBack"));
114 g_sendLayoutMessage = reinterpret_cast<SendLayoutMessage>(dlsym(handlerConnectServerSo_, "SendLayoutMessage"));
115 g_storeInspectorInfo = reinterpret_cast<StoreInspectorInfo>(dlsym(handlerConnectServerSo_, "StoreInspectorInfo"));
116 g_waitForConnection = reinterpret_cast<WaitForConnection>(dlsym(handlerConnectServerSo_, "WaitForConnection"));
117 #else
118 using namespace OHOS::ArkCompiler;
119 g_sendMessage = reinterpret_cast<SendMessage>(&Toolchain::SendMessage);
120 g_storeMessage = reinterpret_cast<StoreMessage>(&Toolchain::StoreMessage);
121 g_removeMessage = reinterpret_cast<RemoveMessage>(&Toolchain::RemoveMessage);
122 g_setSwitchCallBack = reinterpret_cast<SetSwitchCallBack>(&Toolchain::SetSwitchCallBack);
123 g_setDebugModeCallBack = reinterpret_cast<SetDebugModeCallBack>(&Toolchain::SetDebugModeCallBack);
124 g_sendLayoutMessage = reinterpret_cast<SendLayoutMessage>(&Toolchain::SendLayoutMessage);
125 g_storeInspectorInfo = reinterpret_cast<StoreInspectorInfo>(&Toolchain::StoreInspectorInfo);
126 g_waitForConnection = reinterpret_cast<WaitForConnection>(&Toolchain::WaitForConnection);
127 #endif
128 if (g_sendMessage == nullptr || g_storeMessage == nullptr || g_removeMessage == nullptr) {
129 CloseConnectServerSo();
130 return false;
131 }
132
133 if (g_storeInspectorInfo == nullptr || g_setSwitchCallBack == nullptr || g_waitForConnection == nullptr ||
134 g_sendLayoutMessage == nullptr) {
135 CloseConnectServerSo();
136 return false;
137 }
138 return true;
139 }
140
InitConnectServer()141 void ConnectServerManager::InitConnectServer()
142 {
143 #if !defined(IOS_PLATFORM)
144 #if defined(ANDROID_PLATFORM)
145 const std::string soDir = "libconnectserver_debugger.so";
146 #else
147 const std::string soDir = "libconnectserver_debugger.z.so";
148 #endif // ANDROID_PLATFORM
149 handlerConnectServerSo_ = dlopen(soDir.c_str(), RTLD_LAZY);
150 if (handlerConnectServerSo_ == nullptr) {
151 LOGE("Cannot find %{public}s", soDir.c_str());
152 return;
153 }
154 StartServer startServer = reinterpret_cast<StartServer>(dlsym(handlerConnectServerSo_, "StartServer"));
155 if (startServer == nullptr || !InitFunc()) {
156 LOGE("startServer = NULL, dlerror = %s", dlerror());
157 return;
158 }
159 #else
160 StartServer startServer = reinterpret_cast<StartServer>(&ArkCompiler::Toolchain::StartServer);
161 #endif // IOS_PLATFORM
162 startServer(packageName_);
163 g_setDebugModeCallBack([]() {
164 AceApplicationInfo::GetInstance().SetNeedDebugBreakPoint(false);
165 });
166 }
167
StartConnectServerWithSocketPair(int32_t socketFd)168 void ConnectServerManager::StartConnectServerWithSocketPair(int32_t socketFd)
169 {
170 handlerConnectServerSo_ = dlopen("libconnectserver_debugger.z.so", RTLD_LAZY);
171 CHECK_NULL_VOID(handlerConnectServerSo_);
172
173 auto startServerForSocketPair =
174 reinterpret_cast<StartServerForSocketPair>(dlsym(handlerConnectServerSo_, "StartServerForSocketPair"));
175 CHECK_NULL_VOID(startServerForSocketPair);
176 startServerForSocketPair(socketFd);
177 }
178
CloseConnectServerSo()179 void ConnectServerManager::CloseConnectServerSo()
180 {
181 #if !defined(IOS_PLATFORM)
182 CHECK_NULL_VOID(handlerConnectServerSo_);
183 dlclose(handlerConnectServerSo_);
184 handlerConnectServerSo_ = nullptr;
185 #endif
186 }
187
188 // When use multi-instances project, debug mode should be set to support debug
SetDebugMode()189 void ConnectServerManager::SetDebugMode()
190 {
191 if (!CheckDebugVersion()) {
192 return;
193 }
194
195 if (!g_waitForConnection()) { // waitForDebugger : waitForDebugger means the connection state of the connect server
196 AceApplicationInfo::GetInstance().SetNeedDebugBreakPoint(true);
197 }
198 }
199
StopConnectServer()200 void ConnectServerManager::StopConnectServer()
201 {
202 #if !defined(IOS_PLATFORM)
203 CHECK_NULL_VOID(handlerConnectServerSo_);
204 StopServer stopServer = reinterpret_cast<StopServer>(dlsym(handlerConnectServerSo_, "StopServer"));
205 if (stopServer == nullptr) {
206 LOGE("stopServer = NULL, dlerror = %s", dlerror());
207 return;
208 }
209 #else
210 StopServer stopServer = reinterpret_cast<StopServer>(&ArkCompiler::Toolchain::StopServer);
211 #endif
212 stopServer(packageName_);
213 }
214
AddInstance(int32_t instanceId,const std::string & language,const std::string & instanceName)215 void ConnectServerManager::AddInstance(
216 int32_t instanceId, const std::string& language, const std::string& instanceName)
217 {
218 if (!CheckDebugVersion()) {
219 return;
220 }
221 {
222 std::lock_guard<std::mutex> lock(mutex_);
223 const auto result = instanceMap_.try_emplace(instanceId, instanceName);
224 if (!result.second) {
225 return;
226 }
227 }
228 // Get the message including information of new instance, which will be send to IDE.
229 std::string message = GetInstanceMapMessage("addInstance", instanceId, language);
230
231 g_storeMessage(instanceId, message);
232 if (!g_waitForConnection()) { // g_waitForConnection : the res means the connection state of the connect server
233 g_sendMessage(message); // if connected, message will be sent immediately.
234 }
235 CHECK_NULL_VOID(createLayoutInfo_);
236 auto setStatus = [this](bool status) {
237 setStatus_(status);
238 };
239 auto createLayoutInfo = [this](int32_t containerId) {
240 createLayoutInfo_(containerId);
241 };
242 g_setSwitchCallBack(setStatus, createLayoutInfo, instanceId);
243 }
244
SendInspector(const std::string & jsonTreeStr,const std::string & jsonSnapshotStr)245 void ConnectServerManager::SendInspector(const std::string& jsonTreeStr, const std::string& jsonSnapshotStr)
246 {
247 LOGI("ConnectServerManager SendInspector Start");
248 g_sendLayoutMessage(jsonTreeStr);
249 g_sendLayoutMessage(jsonSnapshotStr);
250 g_storeInspectorInfo(jsonTreeStr, jsonSnapshotStr);
251 }
252
RemoveInstance(int32_t instanceId)253 void ConnectServerManager::RemoveInstance(int32_t instanceId)
254 {
255 if (!CheckDebugVersion()) {
256 return;
257 }
258
259 // Get the message including information of deleted instance, which will be send to IDE.
260 std::string message = GetInstanceMapMessage("destroyInstance", instanceId);
261 size_t numInstance = 0;
262 {
263 std::lock_guard<std::mutex> lock(mutex_);
264 numInstance = instanceMap_.erase(instanceId);
265 }
266 if (numInstance == 0) {
267 LOGW("Instance name not found with instance id: %{public}d", instanceId);
268 }
269
270 g_removeMessage(instanceId);
271 if (!g_waitForConnection()) {
272 g_sendMessage(message);
273 }
274 }
275
GetInstanceMapMessage(const char * messageType,int32_t instanceId,const std::string & language)276 std::string ConnectServerManager::GetInstanceMapMessage(
277 const char* messageType, int32_t instanceId, const std::string& language)
278 {
279 std::lock_guard<std::mutex> lock(mutex_);
280 auto message = JsonUtil::Create(true);
281 message->Put("type", messageType);
282 message->Put("instanceId", instanceId);
283 message->Put("name", instanceMap_[instanceId].c_str());
284 #if !defined(IOS_PLATFORM)
285 message->Put("tid", gettid());
286 #else
287 uint64_t tid;
288 pthread_threadid_np(0, &tid);
289 message->Put("tid", static_cast<int64_t>(tid));
290 #endif
291 message->Put("apiType", "faMode");
292 message->Put("language", language.c_str());
293 return message->ToString();
294 }
295
SetLayoutInspectorCallback(const std::function<void (int32_t)> & createLayoutInfo,const std::function<void (bool)> & setStatus)296 void ConnectServerManager::SetLayoutInspectorCallback(
297 const std::function<void(int32_t)>& createLayoutInfo, const std::function<void(bool)>& setStatus)
298 {
299 createLayoutInfo_ = createLayoutInfo;
300 setStatus_ = setStatus;
301 }
302
GetLayoutInspectorCallback()303 std::function<void(int32_t)> ConnectServerManager::GetLayoutInspectorCallback()
304 {
305 return createLayoutInfo_;
306 }
307 } // namespace OHOS::Ace
308