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