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