• 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 <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