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