• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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