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