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