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