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 #include "jdwp.h"
16 #include <sys/eventfd.h>
17 #include <thread>
18 #include "system_depend.h"
19
20 namespace Hdc {
HdcJdwp(uv_loop_t *loopIn)21 HdcJdwp::HdcJdwp(uv_loop_t *loopIn)
22 {
23 listenPipe.data = this;
24 loop = loopIn;
25 refCount = 0;
26 uv_rwlock_init(&lockMapContext);
27 uv_rwlock_init(&lockJdwpTrack);
28 awakenPollFd = -1;
29 stop = false;
30 }
31
~HdcJdwp()32 HdcJdwp::~HdcJdwp()
33 {
34 Base::CloseFd(awakenPollFd);
35 uv_rwlock_destroy(&lockMapContext);
36 uv_rwlock_destroy(&lockJdwpTrack);
37 }
38
ReadyForRelease()39 bool HdcJdwp::ReadyForRelease()
40 {
41 return refCount == 0;
42 }
43
Stop()44 void HdcJdwp::Stop()
45 {
46 stop = true;
47 WakePollThread();
48 auto funcListenPipeClose = [](uv_handle_t *handle) -> void {
49 HdcJdwp *thisClass = (HdcJdwp *)handle->data;
50 --thisClass->refCount;
51 };
52 Base::TryCloseHandle((const uv_handle_t *)&listenPipe, funcListenPipeClose);
53 freeContextMutex.lock();
54 for (auto &&obj : mapCtxJdwp) {
55 HCtxJdwp v = obj.second;
56 FreeContext(v);
57 }
58 AdminContext(OP_CLEAR, 0, nullptr);
59 freeContextMutex.unlock();
60 }
61
MallocContext()62 void *HdcJdwp::MallocContext()
63 {
64 HCtxJdwp ctx = nullptr;
65 if ((ctx = new ContextJdwp()) == nullptr) {
66 return nullptr;
67 }
68 ctx->isDebug = 0;
69 ctx->thisClass = this;
70 ctx->pipe.data = ctx;
71 ++refCount;
72 return ctx;
73 }
74
75 // Single thread, two parameters can be used
FreeContext(HCtxJdwp ctx)76 void HdcJdwp::FreeContext(HCtxJdwp ctx)
77 {
78 if (ctx->finish) {
79 return;
80 }
81 ctx->finish = true;
82 WRITE_LOG(LOG_INFO, "FreeContext for targetPID :%d", ctx->pid);
83 if (!stop) {
84 AdminContext(OP_REMOVE, ctx->pid, nullptr);
85 }
86 auto funcReqClose = [](uv_idle_t *handle) -> void {
87 HCtxJdwp ctxIn = (HCtxJdwp)handle->data;
88 --ctxIn->thisClass->refCount;
89 Base::TryCloseHandle((uv_handle_t *)handle, Base::CloseIdleCallback);
90
91 Base::TryCloseHandle((const uv_handle_t *)&ctxIn->pipe, [](uv_handle_t *handle) {
92 HCtxJdwp ctxIn = (HCtxJdwp)handle->data;
93 #ifndef HDC_EMULATOR
94 if (ctxIn != nullptr) {
95 delete ctxIn;
96 ctxIn = nullptr;
97 }
98 #endif
99 });
100 };
101 Base::IdleUvTask(loop, ctx, funcReqClose);
102 }
103
RemoveFdFromPollList(uint32_t pid)104 void HdcJdwp::RemoveFdFromPollList(uint32_t pid)
105 {
106 for (auto &&pair : pollNodeMap) {
107 if (pair.second.ppid == pid) {
108 WRITE_LOG(LOG_INFO, "RemoveFdFromPollList for pid:%d.", pid);
109 pollNodeMap.erase(pair.second.pollfd.fd);
110 break;
111 }
112 }
113 }
114
ReadStream(uv_stream_t *pipe, ssize_t nread, const uv_buf_t *buf)115 void HdcJdwp::ReadStream(uv_stream_t *pipe, ssize_t nread, const uv_buf_t *buf)
116 {
117 static std::once_flag firstLog;
118 std::call_once(firstLog, [&]() { SystemDepend::SetDevItem("persist.hdc.jdwp", "0"); });
119
120 bool ret = true;
121 if (nread == UV_ENOBUFS) { // It is definite enough, usually only 4 bytes
122 ret = false;
123 WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream IOBuf max");
124 } else if (nread == 0) {
125 return;
126 #ifdef JS_JDWP_CONNECT
127 } else if (nread < signed(JS_PKG_MIN_SIZE + sizeof(JsMsgHeader)) ||
128 nread > signed(JS_PKG_MAX_SIZE + sizeof(JsMsgHeader))) {
129 #else
130 } else if (nread < 0 || nread != 4) { // 4 : 4 bytes
131 #endif // JS_JDWP_CONNECT
132 ret = false;
133 WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream invalid package nread:%d.", nread);
134 }
135
136 HCtxJdwp ctxJdwp = static_cast<HCtxJdwp>(pipe->data);
137 HdcJdwp *thisClass = static_cast<HdcJdwp *>(ctxJdwp->thisClass);
138 if (ret) {
139 uint32_t pid = 0;
140 char *p = ctxJdwp->buf;
141 if (nread == sizeof(uint32_t)) { // Java: pid
142 pid = atoi(p);
143 } else { // JS:pid PkgName
144 #ifdef JS_JDWP_CONNECT
145 // pid isDebug pkgName/processName
146 struct JsMsgHeader *jsMsg = reinterpret_cast<struct JsMsgHeader *>(p);
147 if (jsMsg->msgLen == nread) {
148 pid = jsMsg->pid;
149 string pkgName = string((char *)p + sizeof(JsMsgHeader), jsMsg->msgLen - sizeof(JsMsgHeader));
150 ctxJdwp->pkgName = pkgName;
151 ctxJdwp->isDebug = jsMsg->isDebug;
152 } else {
153 ret = false;
154 WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream invalid js package size %d:%d.", jsMsg->msgLen, nread);
155 }
156 #endif // JS_JDWP_CONNECT
157 }
158 if (pid > 0) {
159 ctxJdwp->pid = pid;
160 #ifdef JS_JDWP_CONNECT
161 WRITE_LOG(LOG_DEBUG, "JDWP accept pid:%d-pkg:%s isDebug:%d",
162 pid, ctxJdwp->pkgName.c_str(), ctxJdwp->isDebug);
163 #else
164 WRITE_LOG(LOG_DEBUG, "JDWP accept pid:%d", pid);
165 #endif // JS_JDWP_CONNECT
166 thisClass->AdminContext(OP_ADD, pid, ctxJdwp);
167 ret = true;
168 int fd = -1;
169 if (uv_fileno(reinterpret_cast<uv_handle_t *>(&(ctxJdwp->pipe)), &fd) < 0) {
170 WRITE_LOG(LOG_DEBUG, "HdcJdwp::ReadStream uv_fileno fail.");
171 } else {
172 thisClass->freeContextMutex.lock();
173 thisClass->pollNodeMap.emplace(fd, PollNode(fd, pid));
174 thisClass->freeContextMutex.unlock();
175 thisClass->WakePollThread();
176 }
177 }
178 }
179 Base::ZeroArray(ctxJdwp->buf);
180 if (!ret) {
181 WRITE_LOG(LOG_INFO, "ReadStream proc:%d err, free it.", ctxJdwp->pid);
182 thisClass->freeContextMutex.lock();
183 thisClass->FreeContext(ctxJdwp);
184 thisClass->freeContextMutex.unlock();
185 }
186 }
187
188 #ifdef JS_JDWP_CONNECT
GetProcessListExtendPkgName(uint8_t dr)189 string HdcJdwp::GetProcessListExtendPkgName(uint8_t dr)
190 {
191 constexpr uint8_t releaseApp = 2;
192 constexpr uint8_t allAppWithDr = 3;
193 string ret;
194 uv_rwlock_rdlock(&lockMapContext);
195 for (auto &&v : mapCtxJdwp) {
196 HCtxJdwp hj = v.second;
197 if (dr == 0) {
198 // allApp
199 ret += std::to_string(v.first) + " " + hj->pkgName + "\n";
200 } else if (dr == 1) {
201 // debugApp
202 if (hj->isDebug) {
203 ret += std::to_string(v.first) + " " + hj->pkgName + "\n";
204 }
205 } else if (dr == releaseApp) {
206 // releaseApp
207 if (!hj->isDebug) {
208 ret += std::to_string(v.first) + " " + hj->pkgName + "\n";
209 }
210 } else if (dr == allAppWithDr) {
211 // allApp with display debug or release
212 string apptype = "release";
213 if (hj->isDebug) {
214 apptype = "debug";
215 }
216 ret += std::to_string(v.first) + " " + hj->pkgName + " " + apptype + "\n";
217 }
218 }
219 uv_rwlock_rdunlock(&lockMapContext);
220 return ret;
221 }
222 #endif // JS_JDWP_CONNECT
223
AcceptClient(uv_stream_t *server, int status)224 void HdcJdwp::AcceptClient(uv_stream_t *server, int status)
225 {
226 uv_pipe_t *listenPipe = (uv_pipe_t *)server;
227 HdcJdwp *thisClass = (HdcJdwp *)listenPipe->data;
228 HCtxJdwp ctxJdwp = (HCtxJdwp)thisClass->MallocContext();
229 if (!ctxJdwp) {
230 return;
231 }
232 uv_pipe_init(thisClass->loop, &ctxJdwp->pipe, 1);
233 if (uv_accept(server, (uv_stream_t *)&ctxJdwp->pipe) < 0) {
234 WRITE_LOG(LOG_DEBUG, "uv_accept failed");
235 thisClass->freeContextMutex.lock();
236 thisClass->FreeContext(ctxJdwp);
237 thisClass->freeContextMutex.unlock();
238 return;
239 }
240 auto funAlloc = [](uv_handle_t *handle, size_t sizeSuggested, uv_buf_t *buf) -> void {
241 HCtxJdwp ctxJdwp = (HCtxJdwp)handle->data;
242 buf->base = (char *)ctxJdwp->buf;
243 buf->len = sizeof(ctxJdwp->buf);
244 };
245 uv_read_start((uv_stream_t *)&ctxJdwp->pipe, funAlloc, ReadStream);
246 }
247
248 // Test bash connnet(UNIX-domain sockets):nc -U path/ohjpid-control < hexpid.file
249 // Test uv connect(pipe): 'uv_pipe_connect'
JdwpListen()250 bool HdcJdwp::JdwpListen()
251 {
252 #ifdef HDC_PCDEBUG
253 // if test, can be enabled
254 return true;
255 const char jdwpCtrlName[] = { 'o', 'h', 'j', 'p', 'i', 'd', '-', 'c', 'o', 'n', 't', 'r', 'o', 'l', 0 };
256 unlink(jdwpCtrlName);
257 #else
258 const char jdwpCtrlName[] = { '\0', 'o', 'h', 'j', 'p', 'i', 'd', '-', 'c', 'o', 'n', 't', 'r', 'o', 'l', 0 };
259 #endif
260 const int DEFAULT_BACKLOG = 4;
261 bool ret = false;
262 while (true) {
263 uv_pipe_init(loop, &listenPipe, 0);
264 listenPipe.data = this;
265 if (UvPipeBind(&listenPipe, jdwpCtrlName, sizeof(jdwpCtrlName))) {
266 WRITE_LOG(LOG_FATAL, "UvPipeBind failed");
267 return ret;
268 }
269 if (uv_listen((uv_stream_t *)&listenPipe, DEFAULT_BACKLOG, AcceptClient)) {
270 WRITE_LOG(LOG_FATAL, "uv_listen failed");
271 break;
272 }
273 ++refCount;
274 ret = true;
275 break;
276 }
277 // listenPipe close by stop
278 return ret;
279 }
280
UvPipeBind(uv_pipe_t* handle, const char* name, size_t size)281 int HdcJdwp::UvPipeBind(uv_pipe_t* handle, const char* name, size_t size)
282 {
283 char buffer[BUF_SIZE_DEFAULT] = { 0 };
284
285 if (handle->io_watcher.fd >= 0) {
286 WRITE_LOG(LOG_FATAL, "socket already bound %d", handle->io_watcher.fd);
287 return -1;
288 }
289
290 int type = SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC;
291 int sockfd = socket(AF_UNIX, type, 0);
292 if (sockfd < 0) {
293 strerror_r(errno, buffer, BUF_SIZE_DEFAULT);
294 WRITE_LOG(LOG_FATAL, "socket failed errno:%d %s", errno, buffer);
295 return -1;
296 }
297
298 #if defined(SO_NOSIGPIPE)
299 int on = 1;
300 setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
301 #endif
302
303 struct sockaddr_un saddr;
304 Base::ZeroStruct(saddr);
305 size_t capacity = sizeof(saddr.sun_path);
306 size_t min = size < capacity ? size : capacity;
307 for (size_t i = 0; i < min; i++) {
308 saddr.sun_path[i] = name[i];
309 }
310 saddr.sun_path[capacity - 1] = '\0';
311 saddr.sun_family = AF_UNIX;
312 size_t saddrLen = sizeof(saddr.sun_family) + size - 1;
313 int err = bind(sockfd, reinterpret_cast<struct sockaddr*>(&saddr), saddrLen);
314 if (err != 0) {
315 strerror_r(errno, buffer, BUF_SIZE_DEFAULT);
316 WRITE_LOG(LOG_FATAL, "bind failed errno:%d %s", errno, buffer);
317 close(sockfd);
318 return -1;
319 }
320 constexpr uint32_t uvHandleBound = 0x00002000;
321 handle->flags |= uvHandleBound;
322 handle->io_watcher.fd = sockfd;
323 return 0;
324 }
325
326 // Working in the main thread, but will be accessed by each session thread, so we need to set thread lock
AdminContext(const uint8_t op, const uint32_t pid, HCtxJdwp ctxJdwp)327 void *HdcJdwp::AdminContext(const uint8_t op, const uint32_t pid, HCtxJdwp ctxJdwp)
328 {
329 HCtxJdwp hRet = nullptr;
330 switch (op) {
331 case OP_ADD: {
332 uv_rwlock_wrlock(&lockMapContext);
333 const int maxMapSize = 1024;
334 if (mapCtxJdwp.size() < maxMapSize) {
335 mapCtxJdwp[pid] = ctxJdwp;
336 }
337 uv_rwlock_wrunlock(&lockMapContext);
338 break;
339 }
340 case OP_REMOVE:
341 uv_rwlock_wrlock(&lockMapContext);
342 mapCtxJdwp.erase(pid);
343 RemoveFdFromPollList(pid);
344 uv_rwlock_wrunlock(&lockMapContext);
345 break;
346 case OP_QUERY: {
347 uv_rwlock_rdlock(&lockMapContext);
348 if (mapCtxJdwp.count(pid)) {
349 hRet = mapCtxJdwp[pid];
350 }
351 uv_rwlock_rdunlock(&lockMapContext);
352 break;
353 }
354 case OP_CLEAR: {
355 uv_rwlock_wrlock(&lockMapContext);
356 mapCtxJdwp.clear();
357 pollNodeMap.clear();
358 uv_rwlock_wrunlock(&lockMapContext);
359 break;
360 }
361 default:
362 break;
363 }
364 if (op == OP_ADD || op == OP_REMOVE || op == OP_CLEAR) {
365 uv_rwlock_wrlock(&lockJdwpTrack);
366 ProcessListUpdated();
367 uv_rwlock_wrunlock(&lockJdwpTrack);
368 }
369 return hRet;
370 }
371
372 // work on main thread
SendCallbackJdwpNewFD(uv_write_t *req, int status)373 void HdcJdwp::SendCallbackJdwpNewFD(uv_write_t *req, int status)
374 {
375 // It usually works successful, not notify session work
376 HCtxJdwp ctx = (HCtxJdwp)req->data;
377 if (status >= 0) {
378 WRITE_LOG(LOG_DEBUG, "SendCallbackJdwpNewFD successful %d, active jdwp forward", ctx->pid);
379 } else {
380 WRITE_LOG(LOG_WARN, "SendCallbackJdwpNewFD failed %d", ctx->pid);
381 }
382 delete req;
383 }
384
385 // Each session calls the interface through the main thread message queue, which cannot be called directly across
386 // threads
387 // work on main thread
SendJdwpNewFD(uint32_t targetPID, int fd)388 bool HdcJdwp::SendJdwpNewFD(uint32_t targetPID, int fd)
389 {
390 bool ret = false;
391 while (true) {
392 HCtxJdwp ctx = (HCtxJdwp)AdminContext(OP_QUERY, targetPID, nullptr);
393 if (!ctx) {
394 break;
395 }
396 ctx->dummy = static_cast<uint8_t>('!');
397 if (uv_tcp_init(loop, &ctx->jvmTCP)) {
398 break;
399 }
400 if (uv_tcp_open(&ctx->jvmTCP, fd)) {
401 break;
402 }
403 // transfer fd to jvm
404 // clang-format off
405 if (Base::SendToStreamEx((uv_stream_t *)&ctx->pipe, (uint8_t *)&ctx->dummy, 1, (uv_stream_t *)&ctx->jvmTCP,
406 (void *)SendCallbackJdwpNewFD, (const void *)ctx) < 0) {
407 break;
408 }
409 // clang-format on
410 ++refCount;
411 ret = true;
412 WRITE_LOG(LOG_DEBUG, "SendJdwpNewFD successful targetPID:%d fd%d", targetPID, fd);
413 break;
414 }
415 return ret;
416 }
417
SendArkNewFD(const std::string str, int fd)418 bool HdcJdwp::SendArkNewFD(const std::string str, int fd)
419 {
420 bool ret = false;
421 while (true) {
422 // str(ark:pid@tid@Debugger)
423 size_t pos = str.find_first_of(':');
424 std::string right = str.substr(pos + 1);
425 pos = right.find_first_of("@");
426 std::string pidstr = right.substr(0, pos);
427 uint32_t pid = static_cast<uint32_t>(std::atoi(pidstr.c_str()));
428 HCtxJdwp ctx = (HCtxJdwp)AdminContext(OP_QUERY, pid, nullptr);
429 if (!ctx) {
430 WRITE_LOG(LOG_FATAL, "SendArkNewFD query pid:%u failed", pid);
431 break;
432 }
433 uint32_t size = sizeof(int32_t) + str.size();
434 // fd | str(ark:pid@tid@Debugger)
435 uint8_t buf[size];
436 if (memcpy_s(buf, sizeof(int32_t), &fd, sizeof(int32_t)) != EOK) {
437 WRITE_LOG(LOG_WARN, "From fd Create buf failed, fd:%d", fd);
438 return false;
439 }
440 if (memcpy_s(buf + sizeof(int32_t), str.size(), str.c_str(), str.size()) != EOK) {
441 WRITE_LOG(LOG_WARN, "SendArkNewFD failed fd:%d str:%s", fd, str.c_str());
442 return false;
443 }
444 uv_stream_t *stream = (uv_stream_t *)&ctx->pipe;
445 SendFdToApp(stream->io_watcher.fd, buf, size, fd);
446 ret = true;
447 WRITE_LOG(LOG_DEBUG, "SendArkNewFD successful str:%s fd%d", str.c_str(), fd);
448 Base::CloseFd(fd);
449 break;
450 }
451 return ret;
452 }
453
SendFdToApp(int sockfd, uint8_t *buf, int size, int fd)454 bool HdcJdwp::SendFdToApp(int sockfd, uint8_t *buf, int size, int fd)
455 {
456 struct iovec iov;
457 iov.iov_base = buf;
458 iov.iov_len = static_cast<unsigned int>(size);
459 struct msghdr msg;
460 msg.msg_name = nullptr;
461 msg.msg_namelen = 0;
462 msg.msg_iov = &iov;
463 msg.msg_iovlen = 1;
464
465 int len = CMSG_SPACE(static_cast<unsigned int>(sizeof(fd)));
466 char ctlBuf[len];
467 msg.msg_control = ctlBuf;
468 msg.msg_controllen = sizeof(ctlBuf);
469
470 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
471 if (cmsg == nullptr) {
472 WRITE_LOG(LOG_FATAL, "SendFdToApp cmsg is nullptr");
473 return false;
474 }
475 cmsg->cmsg_level = SOL_SOCKET;
476 cmsg->cmsg_type = SCM_RIGHTS;
477 cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
478 if (memcpy_s(CMSG_DATA(cmsg), sizeof(fd), &fd, sizeof(fd)) != 0) {
479 WRITE_LOG(LOG_FATAL, "SendFdToApp memcpy error:%d", errno);
480 return false;
481 }
482 if (sendmsg(sockfd, &msg, 0) < 0) {
483 WRITE_LOG(LOG_FATAL, "SendFdToApp sendmsg errno:%d", errno);
484 return false;
485 }
486 return true;
487 }
488
489 // cross thread call begin
CheckPIDExist(uint32_t targetPID)490 bool HdcJdwp::CheckPIDExist(uint32_t targetPID)
491 {
492 HCtxJdwp ctx = (HCtxJdwp)AdminContext(OP_QUERY, targetPID, nullptr);
493 return ctx != nullptr;
494 }
495
GetProcessList()496 string HdcJdwp::GetProcessList()
497 {
498 string ret;
499 uv_rwlock_rdlock(&lockMapContext);
500 for (auto &&v : mapCtxJdwp) {
501 ret += std::to_string(v.first) + "\n";
502 }
503 uv_rwlock_rdunlock(&lockMapContext);
504 return ret;
505 }
506 // cross thread call finish
507
JdwpProcessListMsg(char *buffer, size_t bufferlen, uint8_t dr)508 size_t HdcJdwp::JdwpProcessListMsg(char *buffer, size_t bufferlen, uint8_t dr)
509 {
510 // Message is length-prefixed with 4 hex digits in ASCII.
511 static constexpr size_t headerLen = 5;
512 char head[headerLen + 2];
513 #ifdef JS_JDWP_CONNECT
514 string result = GetProcessListExtendPkgName(dr);
515 #else
516 string result = GetProcessList();
517 #endif // JS_JDWP_CONNECT
518
519 size_t len = result.length();
520 if (bufferlen < (len + headerLen)) {
521 WRITE_LOG(LOG_WARN, "truncating JDWP process list (max len = %zu) ", bufferlen);
522 len = bufferlen;
523 }
524 if (snprintf_s(head, sizeof head, sizeof head - 1, "%04zx\n", len) < 0) {
525 WRITE_LOG(LOG_WARN, " JdwpProcessListMsg head fail.");
526 return 0;
527 }
528 if (memcpy_s(buffer, bufferlen, head, headerLen) != EOK) {
529 WRITE_LOG(LOG_WARN, " JdwpProcessListMsg get head fail.");
530 return 0;
531 }
532 if (memcpy_s(buffer + headerLen, (bufferlen - headerLen), result.c_str(), len) != EOK) {
533 WRITE_LOG(LOG_WARN, " JdwpProcessListMsg get data fail.");
534 return 0;
535 }
536 return len + headerLen;
537 }
538
SendProcessList(HTaskInfo t, string data)539 void HdcJdwp::SendProcessList(HTaskInfo t, string data)
540 {
541 if (t == nullptr || data.size() == 0) {
542 WRITE_LOG(LOG_WARN, " SendProcessList, Nothing needs to be sent.");
543 return;
544 }
545 void *clsSession = t->ownerSessionClass;
546 HdcSessionBase *sessionBase = static_cast<HdcSessionBase *>(clsSession);
547 sessionBase->LogMsg(t->sessionId, t->channelId, MSG_OK, data.c_str());
548 }
549
ProcessListUpdated(HTaskInfo task)550 void HdcJdwp::ProcessListUpdated(HTaskInfo task)
551 {
552 if (jdwpTrackers.size() <= 0) {
553 return;
554 }
555 #ifdef JS_JDWP_CONNECT
556 static constexpr uint32_t jpidTrackListSize = 1024 * 4;
557 #else
558 static constexpr uint32_t jpidTrackListSize = 1024;
559 #endif // JS_JDWP_CONNECT
560 std::string data;
561 if (task != nullptr) {
562 data.resize(jpidTrackListSize);
563 size_t len = JdwpProcessListMsg(&data[0], data.size(), task->debugRelease);
564 if (len > 0) {
565 data.resize(len);
566 SendProcessList(task, data);
567 }
568 return;
569 }
570 for (auto iter = jdwpTrackers.begin(); iter != jdwpTrackers.end();) {
571 if (*iter == nullptr) {
572 continue;
573 }
574 // The channel for the track-jpid has been stopped.
575 if ((*iter)->taskStop || (*iter)->taskFree || !(*iter)->taskClass) {
576 iter = jdwpTrackers.erase(remove(jdwpTrackers.begin(), jdwpTrackers.end(), *iter), jdwpTrackers.end());
577 if (jdwpTrackers.size() == 0) {
578 return;
579 }
580 } else {
581 data.resize(jpidTrackListSize);
582 size_t len = JdwpProcessListMsg(&data[0], data.size(), (*iter)->debugRelease);
583 if (len > 0) {
584 data.resize(len);
585 SendProcessList(*iter, data);
586 }
587 iter++;
588 }
589 }
590 }
591
CreateJdwpTracker(HTaskInfo taskInfo)592 bool HdcJdwp::CreateJdwpTracker(HTaskInfo taskInfo)
593 {
594 if (taskInfo == nullptr) {
595 return false;
596 }
597 uv_rwlock_wrlock(&lockJdwpTrack);
598 auto it = std::find(jdwpTrackers.begin(), jdwpTrackers.end(), taskInfo);
599 if (it == jdwpTrackers.end()) {
600 jdwpTrackers.push_back(taskInfo);
601 }
602 ProcessListUpdated(taskInfo);
603 uv_rwlock_wrunlock(&lockJdwpTrack);
604 return true;
605 }
606
RemoveJdwpTracker(HTaskInfo taskInfo)607 void HdcJdwp::RemoveJdwpTracker(HTaskInfo taskInfo)
608 {
609 if (taskInfo == nullptr) {
610 return;
611 }
612 uv_rwlock_wrlock(&lockJdwpTrack);
613 auto it = std::find(jdwpTrackers.begin(), jdwpTrackers.end(), taskInfo);
614 if (it != jdwpTrackers.end()) {
615 WRITE_LOG(LOG_DEBUG, "RemoveJdwpTracker channelId:%d, taskType:%d.", taskInfo->channelId, taskInfo->taskType);
616 jdwpTrackers.erase(remove(jdwpTrackers.begin(), jdwpTrackers.end(), *it), jdwpTrackers.end());
617 }
618 uv_rwlock_wrunlock(&lockJdwpTrack);
619 }
620
DrainAwakenPollThread() const621 void HdcJdwp::DrainAwakenPollThread() const
622 {
623 uint64_t value = 0;
624 ssize_t retVal = read(awakenPollFd, &value, sizeof(value));
625 if (retVal < 0) {
626 WRITE_LOG(LOG_FATAL, "DrainAwakenPollThread: Failed to read data from awaken pipe %d", retVal);
627 }
628 }
629
WakePollThread()630 void HdcJdwp::WakePollThread()
631 {
632 if (awakenPollFd < 0) {
633 WRITE_LOG(LOG_DEBUG, "awakenPollFd: MUST initialized before notifying");
634 return;
635 }
636 static const uint64_t increment = 1;
637 ssize_t retVal = write(awakenPollFd, &increment, sizeof(increment));
638 if (retVal < 0) {
639 WRITE_LOG(LOG_FATAL, "WakePollThread: Failed to write data into awaken pipe %d", retVal);
640 }
641 }
642
FdEventPollThread(void *args)643 void *HdcJdwp::FdEventPollThread(void *args)
644 {
645 auto thisClass = static_cast<HdcJdwp *>(args);
646 std::vector<struct pollfd> pollfds;
647 size_t size = 0;
648 while (!thisClass->stop) {
649 thisClass->freeContextMutex.lock();
650 if (size != thisClass->pollNodeMap.size() || thisClass->pollNodeMap.size() == 0) {
651 pollfds.clear();
652 struct pollfd pollFd;
653 for (const auto &pair : thisClass->pollNodeMap) {
654 pollFd.fd = pair.second.pollfd.fd;
655 pollFd.events = pair.second.pollfd.events;
656 pollFd.revents = pair.second.pollfd.revents;
657 pollfds.push_back(pollFd);
658 }
659 pollFd.fd = thisClass->awakenPollFd;
660 pollFd.events = POLLIN;
661 pollFd.revents = 0;
662 pollfds.push_back(pollFd);
663 size = pollfds.size();
664 }
665 thisClass->freeContextMutex.unlock();
666 poll(&pollfds[0], size, -1);
667 for (const auto &pollfdsing : pollfds) {
668 if (pollfdsing.revents & (POLLNVAL | POLLRDHUP | POLLHUP | POLLERR)) { // POLLNVAL:fd not open
669 thisClass->freeContextMutex.lock();
670 auto it = thisClass->pollNodeMap.find(pollfdsing.fd);
671 if (it != thisClass->pollNodeMap.end()) {
672 uint32_t targetPID = it->second.ppid;
673 HCtxJdwp ctx = static_cast<HCtxJdwp>(thisClass->AdminContext(OP_QUERY, targetPID, nullptr));
674 if (ctx != nullptr) {
675 thisClass->AdminContext(OP_REMOVE, targetPID, nullptr);
676 }
677 }
678 thisClass->freeContextMutex.unlock();
679 } else if (pollfdsing.revents & POLLIN) {
680 if (pollfdsing.fd == thisClass->awakenPollFd) {
681 thisClass->DrainAwakenPollThread();
682 }
683 }
684 }
685 }
686 return nullptr;
687 }
688
CreateFdEventPoll()689 int HdcJdwp::CreateFdEventPoll()
690 {
691 pthread_t tid;
692 Base::CloseFd(awakenPollFd);
693 awakenPollFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
694 if (awakenPollFd < 0) {
695 WRITE_LOG(LOG_FATAL, "CreateFdEventPoll : Failed to create awakenPollFd");
696 return ERR_GENERIC;
697 }
698 int tret = pthread_create(&tid, nullptr, FdEventPollThread, this);
699 if (tret != 0) {
700 WRITE_LOG(LOG_INFO, "FdEventPollThread create fail.");
701 return tret;
702 }
703 return RET_SUCCESS;
704 }
705
706 // jdb -connect com.sun.jdi.SocketAttach:hostname=localhost,port=8000
Initial()707 int HdcJdwp::Initial()
708 {
709 freeContextMutex.lock();
710 pollNodeMap.clear();
711 freeContextMutex.unlock();
712 if (!JdwpListen()) {
713 WRITE_LOG(LOG_FATAL, "JdwpListen failed");
714 return ERR_MODULE_JDWP_FAILED;
715 }
716 SystemDepend::SetDevItem("persist.hdc.jdwp", "0");
717 SystemDepend::SetDevItem("persist.hdc.jdwp", "1");
718 if (CreateFdEventPoll() < 0) {
719 return ERR_MODULE_JDWP_FAILED;
720 }
721 return RET_SUCCESS;
722 }
723 }
724