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 char pid[5] = {0};
231 if (sprintf_s(pid, sizeof(pid), "%d", pidCurr) < 0) {
232 HiLog::Info(LABEL, "ConnectJdwp trans pid fail :%{public}d.", pidCurr);
233 return;
234 }
235 HiLog::Info(LABEL, "ConnectJdwp send pid:%{public}s", pid);
236 thisClass->SendToStream(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe),
237 reinterpret_cast<uint8_t *>(pid), sizeof(pidCurr),
238 (void *)FinishWriteCallback);
239 HiLog::Info(LABEL, "ConnectJdwp reading.");
240 uv_read_start(reinterpret_cast<uv_stream_t *>(&ctxJdwp->pipe), thisClass->alloc_buffer,
241 ReceiveNewFd);
242 #endif // JS_JDWP_CONNECT
243 }
244
MallocContext()245 void *HdcJdwpSimulator::MallocContext()
246 {
247 HCtxJdwpSimulator ctx = nullptr;
248 if ((ctx = new ContextJdwpSimulator()) == nullptr) {
249 return nullptr;
250 }
251 ctx->thisClass = this;
252 ctx->pipe.data = ctx;
253 ctx->hasNewFd = false;
254 return ctx;
255 }
256
FreeContext()257 void HdcJdwpSimulator::FreeContext()
258 {
259 HiLog::Debug(LABEL, "HdcJdwpSimulator::FreeContext start");
260 if (!ctxPoint) {
261 return;
262 }
263 if (loop && !uv_is_closing(reinterpret_cast<uv_handle_t *>(&ctxPoint->pipe))) {
264 uv_close(reinterpret_cast<uv_handle_t *>(&ctxPoint->pipe), nullptr);
265 }
266 if (ctxPoint->hasNewFd && loop &&
267 !uv_is_closing(reinterpret_cast<uv_handle_t *>(&ctxPoint->newFd))) {
268 uv_close(reinterpret_cast<uv_handle_t *>(&ctxPoint->newFd), nullptr);
269 }
270 delete ctxPoint;
271 ctxPoint = nullptr;
272 HiLog::Debug(LABEL, "HdcJdwpSimulator::FreeContext end");
273 }
274
Connect()275 bool HdcJdwpSimulator::Connect()
276 {
277 string jdwpCtrlName = "\0ohjpid-control";
278 uv_connect_t *connect = new uv_connect_t();
279 ctxPoint = static_cast<HCtxJdwpSimulator>(MallocContext());
280 if (!ctxPoint) {
281 HiLog::Info(LABEL, "MallocContext failed");
282 return false;
283 }
284 connect->data = ctxPoint;
285 uv_pipe_init(loop, static_cast<uv_pipe_t *>(&ctxPoint->pipe), 1);
286 HiLog::Info(LABEL, " HdcJdwpSimulator Connect begin");
287 uv_pipe_connect(connect, &ctxPoint->pipe, jdwpCtrlName.c_str(), ConnectJdwp);
288 return true;
289 }
290
stop()291 void HdcJdwpSimulator::stop()
292 {
293 HiLog::Debug(LABEL, "HdcJdwpSimulator::stop.");
294 FreeContext();
295 }
296