1 /*
2  * Copyright (c) 2023 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 "tooling/client/domain/runtime_client.h"
17 
18 #include "common/log_wrapper.h"
19 #include "tooling/client/manager/variable_manager.h"
20 #include "tooling/client/manager/watch_manager.h"
21 #include "tooling/base/pt_json.h"
22 #include "tooling/client/session/session.h"
23 #include "tooling/utils/utils.h"
24 
25 using PtJson = panda::ecmascript::tooling::PtJson;
26 namespace OHOS::ArkCompiler::Toolchain {
DispatcherCmd(const std::string &cmd)27 bool RuntimeClient::DispatcherCmd(const std::string &cmd)
28 {
29     std::map<std::string, std::function<int()>> dispatcherTable {
30         { "heapusage", std::bind(&RuntimeClient::HeapusageCommand, this)},
31         { "runtime-enable", std::bind(&RuntimeClient::RuntimeEnableCommand, this)},
32         { "runtime-disable", std::bind(&RuntimeClient::RuntimeDisableCommand, this)},
33         { "print", std::bind(&RuntimeClient::GetPropertiesCommand, this)},
34         { "run", std::bind(&RuntimeClient::RunIfWaitingForDebuggerCommand, this)},
35     };
36 
37     auto entry = dispatcherTable.find(cmd);
38     if (entry != dispatcherTable.end()) {
39         entry->second();
40         LOGI("RuntimeClient DispatcherCmd reqStr1: %{public}s", cmd.c_str());
41         return true;
42     } else {
43         LOGI("Unknown commond: %{public}s", cmd.c_str());
44         return false;
45     }
46 }
47 
HeapusageCommand()48 int RuntimeClient::HeapusageCommand()
49 {
50     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
51     uint32_t id = session->GetMessageId();
52 
53     idMethodMap_[id] = std::make_tuple("getHeapUsage", "");
54     std::unique_ptr<PtJson> request = PtJson::CreateObject();
55     request->Add("id", id);
56     request->Add("method", "Runtime.getHeapUsage");
57 
58     std::unique_ptr<PtJson> params = PtJson::CreateObject();
59     request->Add("params", params);
60 
61     std::string message = request->Stringify();
62     if (session->ClientSendReq(message)) {
63         session->GetDomainManager().SetDomainById(id, "Runtime");
64     }
65     return 0;
66 }
67 
RuntimeEnableCommand()68 int RuntimeClient::RuntimeEnableCommand()
69 {
70     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
71     uint32_t id = session->GetMessageId();
72 
73     idMethodMap_[id] = std::make_tuple("enable", "");
74     std::unique_ptr<PtJson> request = PtJson::CreateObject();
75     request->Add("id", id);
76     request->Add("method", "Runtime.enable");
77 
78     std::unique_ptr<PtJson> params = PtJson::CreateObject();
79     request->Add("params", params);
80 
81     std::string message = request->Stringify();
82     if (session->ClientSendReq(message)) {
83         session->GetDomainManager().SetDomainById(id, "Runtime");
84     }
85     return 0;
86 }
87 
RuntimeDisableCommand()88 int RuntimeClient::RuntimeDisableCommand()
89 {
90     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
91     uint32_t id = session->GetMessageId();
92 
93     idMethodMap_[id] = std::make_tuple("disable", "");
94     std::unique_ptr<PtJson> request = PtJson::CreateObject();
95     request->Add("id", id);
96     request->Add("method", "Runtime.disable");
97 
98     std::unique_ptr<PtJson> params = PtJson::CreateObject();
99     request->Add("params", params);
100 
101     std::string message = request->Stringify();
102     if (session->ClientSendReq(message)) {
103         session->GetDomainManager().SetDomainById(id, "Runtime");
104     }
105     return 0;
106 }
107 
RunIfWaitingForDebuggerCommand()108 int RuntimeClient::RunIfWaitingForDebuggerCommand()
109 {
110     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
111     uint32_t id = session->GetMessageId();
112 
113     idMethodMap_[id] = std::make_tuple("runIfWaitingForDebugger", "");
114     std::unique_ptr<PtJson> request = PtJson::CreateObject();
115     request->Add("id", id);
116     request->Add("method", "Runtime.runIfWaitingForDebugger");
117 
118     std::unique_ptr<PtJson> params = PtJson::CreateObject();
119     request->Add("params", params);
120 
121     std::string message = request->Stringify();
122     if (session->ClientSendReq(message)) {
123         session->GetDomainManager().SetDomainById(id, "Runtime");
124     }
125     WatchManager &watchManager = session->GetWatchManager();
126     watchManager.DebugFalseState();
127     return 0;
128 }
129 
GetPropertiesCommand()130 int RuntimeClient::GetPropertiesCommand()
131 {
132     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
133     uint32_t id = session->GetMessageId();
134 
135     idMethodMap_[id] = std::make_tuple("getProperties", objectId_);
136     std::unique_ptr<PtJson> request = PtJson::CreateObject();
137     request->Add("id", id);
138     request->Add("method", "Runtime.getProperties");
139 
140     std::unique_ptr<PtJson> params = PtJson::CreateObject();
141     params->Add("accessorPropertiesOnly", false);
142     params->Add("generatePreview", true);
143     params->Add("objectId", objectId_.c_str());
144     params->Add("ownProperties", true);
145     request->Add("params", params);
146 
147     std::string message = request->Stringify();
148     if (session->ClientSendReq(message)) {
149         session->GetDomainManager().SetDomainById(id, "Runtime");
150     }
151     return 0;
152 }
153 
GetPropertiesCommand2()154 int RuntimeClient::GetPropertiesCommand2()
155 {
156     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
157     uint32_t id = session->GetMessageId();
158 
159     idMethodMap_[id] = std::make_tuple("getProperties", objectId_);
160     std::unique_ptr<PtJson> request = PtJson::CreateObject();
161     request->Add("id", id);
162     request->Add("method", "Runtime.getProperties");
163 
164     std::unique_ptr<PtJson> params = PtJson::CreateObject();
165     params->Add("accessorPropertiesOnly", true);
166     params->Add("generatePreview", true);
167     params->Add("objectId", "0");
168     params->Add("ownProperties", false);
169     request->Add("params", params);
170 
171     std::string message = request->Stringify();
172     if (session->ClientSendReq(message)) {
173         session->GetDomainManager().SetDomainById(id, "Runtime");
174     }
175     return 0;
176 }
177 
RecvReply(std::unique_ptr<PtJson> json)178 void RuntimeClient::RecvReply(std::unique_ptr<PtJson> json)
179 {
180     if (json == nullptr) {
181         LOGE("arkdb: json parse error");
182         return;
183     }
184 
185     if (!json->IsObject()) {
186         LOGE("arkdb: json parse format error");
187         json->ReleaseRoot();
188         return;
189     }
190 
191     int replyId;
192     Result ret = json->GetInt("id", &replyId);
193     if (ret != Result::SUCCESS) {
194         LOGE("arkdb: find id error");
195         return;
196     }
197 
198     if (GetMethodById(replyId) == "getHeapUsage") {
199         HandleHeapUsage(std::move(json));
200     } else if (GetMethodById(replyId) == "getProperties") {
201         HandleGetProperties(std::move(json), replyId);
202     } else {
203         LOGI("arkdb: Runtime replay message is %{public}s", json->Stringify().c_str());
204     }
205 }
206 
GetMethodById(const int &id)207 std::string RuntimeClient::GetMethodById(const int &id)
208 {
209     auto it = idMethodMap_.find(id);
210     if (it != idMethodMap_.end()) {
211         return std::get<0>(it->second);
212     }
213     return "";
214 }
215 
GetRequestObjectIdById(const int &id)216 std::string RuntimeClient::GetRequestObjectIdById(const int &id)
217 {
218     auto it = idMethodMap_.find(id);
219     if (it != idMethodMap_.end()) {
220         return std::get<1>(it->second);
221     }
222     return "";
223 }
224 
HandleGetProperties(std::unique_ptr<PtJson> json, const int &id)225 void RuntimeClient::HandleGetProperties(std::unique_ptr<PtJson> json, const int &id)
226 {
227     if (json == nullptr) {
228         LOGE("arkdb: json parse error");
229         return;
230     }
231 
232     if (!json->IsObject()) {
233         LOGE("arkdb: json parse format error");
234         json->ReleaseRoot();
235         return;
236     }
237 
238     std::unique_ptr<PtJson> result;
239     Result ret = json->GetObject("result", &result);
240     if (ret != Result::SUCCESS) {
241         LOGE("arkdb: find result error");
242         return;
243     }
244 
245     std::unique_ptr<PtJson> innerResult;
246     ret = result->GetArray("result", &innerResult);
247     if (ret != Result::SUCCESS) {
248         LOGE("arkdb: find innerResult error");
249         return;
250     }
251 
252     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
253     StackManager &stackManager = session->GetStackManager();
254     VariableManager &variableManager = session->GetVariableManager();
255     std::map<int32_t, std::map<int32_t, std::string>> treeInfo = stackManager.GetScopeChainInfo();
256     if (isInitializeTree_) {
257         variableManager.ClearVariableInfo();
258         variableManager.InitializeTree(treeInfo);
259     }
260     std::string requestObjectIdStr = GetRequestObjectIdById(id);
261     TreeNode *node = nullptr;
262     if (!isInitializeTree_) {
263         int32_t requestObjectId;
264         if (!Utils::StrToInt32(requestObjectIdStr, requestObjectId)) {
265             LOGE("arkdb: convert 'requestObjectId' from string to int error");
266             return;
267         }
268         node = variableManager.FindNodeWithObjectId(requestObjectId);
269     } else {
270         node = variableManager.FindNodeObjectZero();
271     }
272 
273     for (int32_t i = 0; i < innerResult->GetSize(); i++) {
274         std::unique_ptr<PropertyDescriptor> variableInfo = PropertyDescriptor::Create(*(innerResult->Get(i)));
275         variableManager.AddVariableInfo(node, std::move(variableInfo));
276     }
277 
278     std::cout << std::endl;
279     variableManager.PrintVariableInfo();
280 }
281 
HandleHeapUsage(std::unique_ptr<PtJson> json)282 void RuntimeClient::HandleHeapUsage(std::unique_ptr<PtJson> json)
283 {
284     if (json == nullptr) {
285         LOGE("arkdb: json parse error");
286         return;
287     }
288 
289     if (!json->IsObject()) {
290         LOGE("arkdb: json parse format error");
291         json->ReleaseRoot();
292         return;
293     }
294 
295     std::unique_ptr<PtJson> result;
296     Result ret = json->GetObject("result", &result);
297     if (ret != Result::SUCCESS) {
298         LOGE("arkdb: find result error");
299         return;
300     }
301 
302     Session *session = SessionManager::getInstance().GetSessionById(sessionId_);
303     VariableManager &variableManager = session->GetVariableManager();
304     std::unique_ptr<GetHeapUsageReturns> heapUsageReturns = GetHeapUsageReturns::Create(*result);
305     variableManager.SetHeapUsageInfo(std::move(heapUsageReturns));
306     variableManager.ShowHeapUsageInfo();
307 }
308 } // OHOS::ArkCompiler::Toolchain