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