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 "HdcJdwpSimulator.h"
17 using namespace OHOS;
18 using namespace OHOS::HiviewDFX;
19 static constexpr HiLogLabel LABEL = {LOG_CORE, 0, "JDWP_TEST"};
HdcJdwpSimulator(uv_loop_t * loopIn,string pkg)20 HdcJdwpSimulator::HdcJdwpSimulator(uv_loop_t *loopIn, string pkg)
21 {
22 loop = loopIn;
23 exit = false;
24 pkgName = pkg;
25 }
26
~HdcJdwpSimulator()27 HdcJdwpSimulator::~HdcJdwpSimulator() {}
28
FinishWriteCallback(uv_write_t * req,int status)29 void HdcJdwpSimulator::FinishWriteCallback(uv_write_t *req, int status)
30 {
31 constexpr int bufSize = 1024;
32 char buf[bufSize] = { 0 };
33 uv_err_name_r(status, buf, bufSize);
34 HiLog::Info(LABEL, "FinishWriteCallback:%{public}d error:%{public}s", status, buf);
35 delete[](static_cast<uint8_t *>(req->data));
36 delete req;
37 }
38
SendToStream(uv_stream_t * handleStream,const uint8_t * buf,const int bufLen,const void * finishCallback)39 RetErrCode HdcJdwpSimulator::SendToStream(uv_stream_t *handleStream, const uint8_t *buf,
40 const int bufLen, const void *finishCallback)
41 {
42 HiLog::Info(LABEL, "HdcJdwpSimulator::SendToStream: %{public}s, %{public}d", buf, bufLen);
43 RetErrCode ret = RetErrCode::ERR_GENERIC;
44 if (bufLen <= 0) {
45 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream wrong bufLen.");
46 return RetErrCode::ERR_GENERIC;
47 }
48 uint8_t *pDynBuf = new uint8_t[bufLen];
49 if (!pDynBuf) {
50 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream new pDynBuf fail.");
51 return RetErrCode::ERR_GENERIC;
52 }
53 if (memcpy_s(pDynBuf, bufLen, buf, bufLen)) {
54 delete[] pDynBuf;
55 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream memcpy fail.");
56 return RetErrCode::ERR_BUF_ALLOC;
57 }
58
59 uv_write_t *reqWrite = new uv_write_t();
60 if (!reqWrite) {
61 HiLog::Error(LABEL, "HdcJdwpSimulator::SendToStream alloc reqWrite fail.");
62 delete[] pDynBuf;
63 return RetErrCode::ERR_GENERIC;
64 }
65 uv_buf_t bfr;
66 while (true) {
67 reqWrite->data = static_cast<void *>(pDynBuf);
68 bfr.base = reinterpret_cast<char *>(pDynBuf);
69 bfr.len = bufLen;
70 if (!uv_is_writable(handleStream)) {
71 HiLog::Info(LABEL, "SendToStream uv_is_unwritable!");
72 delete[] pDynBuf;
73 delete reqWrite;
74 break;
75 }
76 HiLog::Info(LABEL, "SendToStream buf:%{public}s", pDynBuf);
77 uv_write(reqWrite, handleStream, &bfr, 1, (uv_write_cb)finishCallback);
78 ret = RetErrCode::SUCCESS;
79 break;
80 }
81 return ret;
82 }
83
alloc_buffer(uv_handle_t * handle,size_t suggested_size,uv_buf_t * buf)84 void HdcJdwpSimulator::alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf)
85 {
86 if (suggested_size <= 0) {
87 return;
88 }
89 buf->base = (char *)malloc(suggested_size);
90 buf->len = suggested_size;
91 }
92
93 #ifndef JS_JDWP_CONNECT
94 // Process incoming data. If no data is available, this will block until some
95 // arrives.
ProcessIncoming(uv_stream_t * client,ssize_t nread,const uv_buf_t * buf)96 void HdcJdwpSimulator::ProcessIncoming(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf)
97 {
98 HiLog::Debug(LABEL, "ProcessIncoming :%{public}d", nread);
99 do {
100 if (nread > 0) {
101 std::unique_ptr<char[]> recv = std::make_unique<char[]>(nread + 1);
102 if (memset_s(recv.get(), nread, 0, nread) != EOK) {
103 HiLog::Error(LABEL, "ProcessIncoming memset_s fail.");
104 break;
105 }
106 if (memcpy_s(recv.get(), nread, buf->base, nread) != EOK) {
107 HiLog::Error(LABEL, "ProcessIncoming memcpy_s fail.");
108 break;
109 }
110 for (int i = 0; i < (nread + 1); i++) {
111 HiLog::Info(LABEL, "ProcessIncoming recv2[%{public}d] :%{public}c", i, recv[i]);
112 }
113
114 vector<uint8_t> reply;
115 reply.clear();
116 reply.insert(reply.end(), HANDSHAKE_MESSAGE.c_str(),
117 HANDSHAKE_MESSAGE.c_str() + HANDSHAKE_MESSAGE.size());
118 reply.insert(reply.end(), buf->base, buf->base + nread);
119 HiLog::Info(LABEL, "ProcessIncoming--reply server");
120 uint8_t *buf = reply.data();
121
122 for (int i = 0; i < (HANDSHAKE_MESSAGE.size() + nread + 1); i++) {
123 HiLog::Info(LABEL, "ProcessIncoming reply%{public}d :%{public}c", i, reply[i]);
124 }
125 SendToStream(client, buf, HANDSHAKE_MESSAGE.size() + nread + 1,
126 (void *)FinishWriteCallback);
127 } else {
128 if (nread != UV_EOF) {
129 constexpr int bufSize = 1024;
130 char buffer[bufSize] = { 0 };
131 uv_err_name_r(nread, buffer, bufSize);
132 HiLog::Debug(LABEL, "ProcessIncoming error %s\n", buffer);
133 }
134 uv_close((uv_handle_t *)client, NULL);
135 }
136 } while (false);
137 free(buf->base);
138 }
139
140 // Get new socket fd passed from jdwp control
ReceiveNewFd(uv_stream_t * q,ssize_t nread,const uv_buf_t * buf)141 void HdcJdwpSimulator::ReceiveNewFd(uv_stream_t *q, ssize_t nread, const uv_buf_t *buf)
142 {
143 HCtxJdwpSimulator ctxJdwp = static_cast<HCtxJdwpSimulator>(q->data);
144 HdcJdwpSimulator *thisClass = static_cast<HdcJdwpSimulator *>(ctxJdwp->thisClass);
145 int pidCurr = static_cast<int>(getpid());
146 HiLog::Debug(LABEL, "HdcJdwpSimulator::ReceiveNewFd pid: %{public}d, nread: %{public}d\n",
147 pidCurr, nread);
148 if (nread < 0) {
149 if (nread != UV_EOF) {
150 constexpr int bufSize = 1024;
151 char buffer[bufSize] = { 0 };
152 uv_err_name_r(nread, buffer, bufSize);
153 HiLog::Error(LABEL, "Read error %s\n", buffer);
154 }
155 uv_close((uv_handle_t *)q, NULL);
156 return;
157 }
158
159 uv_pipe_t *pipe = reinterpret_cast<uv_pipe_t *>(q);
160 if (!uv_pipe_pending_count(pipe)) {
161 HiLog::Error(LABEL, "No pending count\n");
162 return;
163 }
164 uv_handle_type pending = uv_pipe_pending_type(pipe);
165 if (pending != UV_TCP) {
166 HiLog::Debug(LABEL, "None TCP type: %{public}d", pending);
167 }
168 uv_tcp_init(thisClass->loop, &ctxJdwp->newFd);
169 if (uv_accept(q, reinterpret_cast<uv_stream_t *>(&ctxJdwp->newFd)) == 0) {
170 uv_os_fd_t fd;
171 ctxJdwp->hasNewFd = true;
172 uv_fileno(reinterpret_cast<const uv_handle_t *>(&ctxJdwp->newFd), &fd);
173 HiLog::Debug(LABEL, "Jdwp forward pid %{public}d: new fd %{public}d\n", getpid(), fd);
174 uv_read_start(reinterpret_cast<uv_stream_t *>(&ctxJdwp->newFd), alloc_buffer,
175 ProcessIncoming);
176 } else {
177 ctxJdwp->hasNewFd = false;
178 uv_close(reinterpret_cast<uv_handle_t *>(&ctxJdwp->newFd), NULL);
179 }
180 }
181 #endif // JS_JDWP_CONNECT
182
ConnectJdwp(uv_connect_t * connection,int status)183 void HdcJdwpSimulator::ConnectJdwp(uv_connect_t *connection, int status)
184 {
185 constexpr int bufSize = 1024;
186 char buf[bufSize] = { 0 };
187 uv_err_name_r(status, buf, bufSize);
188 HiLog::Debug(LABEL, "ConnectJdwp:%{public}d error:%{public}s", status, buf);
189 uint32_t pidCurr = static_cast<uint32_t>(getpid());
190 HCtxJdwpSimulator ctxJdwp = static_cast<HCtxJdwpSimulator>(connection->data);
191 HdcJdwpSimulator *thisClass = static_cast<HdcJdwpSimulator *>(ctxJdwp->thisClass);
192 delete connection;
193
194 #ifdef JS_JDWP_CONNECT
195 string pkgName = thisClass->pkgName;
196 uint32_t pkgSize = pkgName.size() + sizeof(JsMsgHeader); // JsMsgHeader pkgName;
197 uint8_t *info = new uint8_t[pkgSize]();
198 if (!info) {
199 HiLog::Error(LABEL, "ConnectJdwp new info fail.");
200 return;
201 }
202 do {
203 if (memset_s(info, pkgSize, 0, pkgSize) != EOK) {
204 HiLog::Error(LABEL, "ConnectJdwp memset_s fail.");
205 break;
206 }
207 JsMsgHeader *jsMsg = reinterpret_cast<JsMsgHeader *>(info);
208 jsMsg->pid = pidCurr;
209 jsMsg->msgLen = pkgSize;
210 HiLog::Info(LABEL,
211 "ConnectJdwp send pid:%{public}d, pkgName:%{public}s, msgLen:%{public}d,",
212 jsMsg->pid, pkgName.c_str(), jsMsg->msgLen);
213 bool retFail = false;
214 if (memcpy_s(info + sizeof(JsMsgHeader), pkgName.size(), &pkgName[0], pkgName.size()) !=
215 EOK) {
216 HiLog::Error(LABEL, "ConnectJdwp memcpy_s fail :%{public}s.", pkgName.c_str());
217 retFail = true;
218 }
219 if (!retFail) {
220 HiLog::Info(LABEL, "ConnectJdwp send JS msg:%{public}s", info);
221 thisClass->SendToStream(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe), info, pkgSize,
222 (void *)FinishWriteCallback);
223 }
224 } while (false);
225 if (info) {
226 delete[] info;
227 info = nullptr;
228 }
229 #else
230 int pidLength = 5;
231 char pid[pidLength] = {0};
232 if (to_string(pidCurr).length() >= pidLength || sprintf_s(pid, sizeof(pid), "%d", pidCurr) < 0) {
233 HiLog::Info(LABEL, "ConnectJdwp trans pid fail :%{public}d.", pidCurr);
234 return;
235 }
236 HiLog::Info(LABEL, "ConnectJdwp send pid:%{public}s", pid);
237 thisClass->SendToStream(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe),
238 reinterpret_cast<uint8_t *>(pid), sizeof(pidCurr),
239 (void *)FinishWriteCallback);
240 HiLog::Info(LABEL, "ConnectJdwp reading.");
241 uv_read_start(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe), thisClass->alloc_buffer,
242 ReceiveNewFd);
243 #endif // JS_JDWP_CONNECT
244 }
245
MallocContext()246 void *HdcJdwpSimulator::MallocContext()
247 {
248 HCtxJdwpSimulator ctx = nullptr;
249 if ((ctx = new ContextJdwpSimulator()) == nullptr) {
250 return nullptr;
251 }
252 ctx->thisClass = this;
253 ctx->pipe.data = ctx;
254 ctx->hasNewFd = false;
255 return ctx;
256 }
257
FreeContext()258 void HdcJdwpSimulator::FreeContext()
259 {
260 HiLog::Debug(LABEL, "HdcJdwpSimulator::FreeContext start");
261 if (!ctxPoint) {
262 return;
263 }
264 if (loop && !uv_is_closing(reinterpret_cast<uv_handle_t *>(&ctxPoint->pipe))) {
265 uv_close(reinterpret_cast<uv_handle_t *>(&ctxPoint->pipe), nullptr);
266 }
267 if (ctxPoint->hasNewFd && loop &&
268 !uv_is_closing(reinterpret_cast<uv_handle_t *>(&ctxPoint->newFd))) {
269 uv_close(reinterpret_cast<uv_handle_t *>(&ctxPoint->newFd), nullptr);
270 }
271 delete ctxPoint;
272 ctxPoint = nullptr;
273 HiLog::Debug(LABEL, "HdcJdwpSimulator::FreeContext end");
274 }
275
Connect()276 bool HdcJdwpSimulator::Connect()
277 {
278 string jdwpCtrlName = "\0ohjpid-control";
279 uv_connect_t *connect = new uv_connect_t();
280 ctxPoint = static_cast<HCtxJdwpSimulator>(MallocContext());
281 if (!ctxPoint) {
282 HiLog::Info(LABEL, "MallocContext failed");
283 return false;
284 }
285 connect->data = ctxPoint;
286 uv_pipe_init(loop, static_cast<uv_pipe_t *>(&ctxPoint->pipe), 1);
287 HiLog::Info(LABEL, " HdcJdwpSimulator Connect begin");
288 uv_pipe_connect(connect, &ctxPoint->pipe, jdwpCtrlName.c_str(), ConnectJdwp);
289 return true;
290 }
291
stop()292 void HdcJdwpSimulator::stop()
293 {
294 HiLog::Debug(LABEL, "HdcJdwpSimulator::stop.");
295 FreeContext();
296 }
297