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