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
25using PtJson = panda::ecmascript::tooling::PtJson;
26namespace OHOS::ArkCompiler::Toolchain {
27bool 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
48int 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
68int 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
88int 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
108int 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
130int 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
154int 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
178void 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
207std::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
216std::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
225void 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
282void 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