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