1/* 2 * Copyright (C) 2021-2022 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 */ 16#include "hdc_jdwp.h" 17#include "parameter.h" 18#include <sys/epoll.h> 19#include <unistd.h> 20 21namespace Hdc { 22 23HdcJdwpSimulator::HdcJdwpSimulator(const std::string processName, const std::string pkgName, bool isDebug, Callback cb) 24{ 25 processName_ = processName; 26 pkgName_ = pkgName; 27 isDebug_ = isDebug; 28 cb_ = cb; 29 cfd_ = -1; 30 disconnectFlag_ = false; 31 notified_ = false; 32 AddWatchHdcdJdwp(); 33} 34 35void HdcJdwpSimulator::Disconnect() 36{ 37 disconnectFlag_ = true; 38 cv_.notify_one(); 39 if (cfd_ > -1) { 40 shutdown(cfd_, SHUT_RDWR); 41 close(cfd_); 42 cfd_ = -1; 43 } 44} 45 46HdcJdwpSimulator::~HdcJdwpSimulator() 47{ 48 Disconnect(); 49 DelWatchHdcdJdwp(); 50} 51 52bool HdcJdwpSimulator::SendBuf(const uint8_t *buf, const int bufLen) 53{ 54 ssize_t rc = write(cfd_, buf, bufLen); 55 if (rc < 0) { 56 HILOG_FATAL(LOG_CORE, "SendBuf failed errno:%{public}d", errno); 57 return false; 58 } 59 return true; 60} 61 62bool HdcJdwpSimulator::Connect2Jdwp() 63{ 64 const char jdwp[] = { '\0', 'o', 'h', 'j', 'p', 'i', 'd', '-', 'c', 'o', 'n', 't', 'r', 'o', 'l', 0 }; 65 struct sockaddr_un caddr; 66 if (memset_s(&caddr, sizeof(caddr), 0, sizeof(caddr)) != EOK) { 67 HILOG_FATAL(LOG_CORE, "memset_s failed"); 68 return false; 69 } 70 caddr.sun_family = AF_UNIX; 71 for (size_t i = 0; i < sizeof(jdwp); i++) { 72 caddr.sun_path[i] = jdwp[i]; 73 } 74 cfd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); 75 if (cfd_ < 0) { 76 HILOG_FATAL(LOG_CORE, "socket failed errno:%{public}d", errno); 77 return false; 78 } 79 struct timeval timeout; 80 timeout.tv_sec = 1; 81 timeout.tv_usec = 0; 82 setsockopt(cfd_, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)); 83 size_t caddrLen = sizeof(caddr.sun_family) + sizeof(jdwp) - 1; 84 int retry = 3; 85 int rc = 0; 86 while (retry-- > 0) { 87 rc = connect(cfd_, reinterpret_cast<struct sockaddr *>(&caddr), caddrLen); 88 if (rc == 0) { 89 HILOG_INFO(LOG_CORE, "connect success cfd:%{public}d", cfd_); 90 break; 91 } 92 constexpr int to = 3; 93 sleep(to); 94 } 95 if (rc != 0) { 96 HILOG_INFO(LOG_CORE, "connect failed cfd_:%{public}d", cfd_); 97 close(cfd_); 98 cfd_ = -1; 99 return false; 100 } 101 return true; 102} 103 104bool HdcJdwpSimulator::Send2Jdwp() 105{ 106#ifdef JS_JDWP_CONNECT 107 uint32_t pidCurr = static_cast<uint32_t>(getprocpid()); 108 std::string processName = processName_; 109 std::string pkgName = pkgName_; 110 bool isDebug = isDebug_; 111 std::string pp = pkgName; 112 if (!processName.empty()) { 113 pp += "/" + processName; 114 } 115 uint32_t ppSize = pp.size() + sizeof(JsMsgHeader); 116 uint8_t* info = new (std::nothrow) uint8_t[ppSize](); 117 if (info == nullptr) { 118 HILOG_FATAL(LOG_CORE, "Send2Jdwp new info fail."); 119 return false; 120 } 121 if (memset_s(info, ppSize, 0, ppSize) != EOK) { 122 delete[] info; 123 info = nullptr; 124 return false; 125 } 126 JsMsgHeader *jsMsg = reinterpret_cast<JsMsgHeader *>(info); 127 jsMsg->msgLen = ppSize; 128 jsMsg->pid = pidCurr; 129 jsMsg->isDebug = isDebug; 130 HILOG_INFO(LOG_CORE, 131 "Send2Jdwp send pid:%{public}d, pp:%{public}s, isDebug:%{public}d, msglen:%{public}d", 132 jsMsg->pid, pp.c_str(), isDebug, jsMsg->msgLen); 133 bool ret = true; 134 if (memcpy_s(info + sizeof(JsMsgHeader), pp.size(), &pp[0], pp.size()) != EOK) { 135 HILOG_FATAL(LOG_CORE, "Send2Jdwp memcpy_s fail :%{public}s.", pp.c_str()); 136 ret = false; 137 } else { 138 ret = SendBuf(static_cast<uint8_t*>(info), ppSize); 139 } 140 delete[] info; 141 return ret; 142#endif 143 return false; 144} 145 146void HdcJdwpSimulator::ReadFromJdwp() 147{ 148 constexpr size_t size = 256; 149 constexpr long sec = 5; 150 constexpr long ms = 1000; 151 uint8_t buf[size] = { 0 }; 152 constexpr int maxevents = 1; 153 struct epoll_event ev; 154 struct epoll_event evs[maxevents]; 155 int efd = epoll_create(maxevents); 156 if (efd == -1) { 157 HILOG_FATAL(LOG_CORE, "Read epoll_create error:%{public}d", errno); 158 return; 159 } 160 ev.data.fd = cfd_; 161 ev.events = EPOLLIN ; 162 int rc = epoll_ctl(efd, EPOLL_CTL_ADD, cfd_, &ev); 163 if (rc == -1) { 164 HILOG_FATAL(LOG_CORE, "Read epoll_ctl add cfd:%{public}d error:%{public}d", 165 cfd_, errno); 166 close(efd); 167 return; 168 } 169 while (!disconnectFlag_) { 170 ssize_t cnt = 0; 171 ssize_t minlen = sizeof(int32_t); 172 rc = epoll_wait(efd, evs, maxevents, sec * ms); 173 if (rc < 0) { 174 if (errno == EINTR) { 175 continue; 176 } 177 HILOG_FATAL(LOG_CORE, "Read epoll_wait cfd:%{public}d error:%{public}d", 178 cfd_, errno); 179 break; 180 } else if (rc == 0) { 181 continue; 182 } 183 int rfd = evs[0].data.fd; 184 if (memset_s(buf, sizeof(buf), 0, sizeof(buf)) != EOK) { 185 continue; 186 } 187 struct iovec iov; 188 iov.iov_base = buf; 189 iov.iov_len = size - 1; 190 struct msghdr msg; 191 msg.msg_iov = &iov; 192 msg.msg_iovlen = 1; 193 int len = CMSG_SPACE(static_cast<unsigned int>(sizeof(int))); 194 char ctlBuf[len]; 195 msg.msg_controllen = sizeof(ctlBuf); 196 msg.msg_control = ctlBuf; 197 cnt = recvmsg(rfd, &msg, 0); 198 if (cnt < 0) { 199 HILOG_FATAL(LOG_CORE, "Read recvmsg rfd:%{public}d errno:%{public}d", rfd, errno); 200 break; 201 } else if (cnt == 0) { 202 HILOG_WARN(LOG_CORE, "Read recvmsg socket peer closed rfd:%{public}d", rfd); 203 break; 204 } else if (cnt < minlen) { 205 HILOG_WARN(LOG_CORE, "Read recvmsg cnt:%{public}zd rfd:%{public}d", cnt, rfd); 206 continue; 207 } 208 int32_t fd = *reinterpret_cast<int32_t *>(buf); 209 std::string str(reinterpret_cast<char *>(buf + sizeof(int32_t)), cnt - sizeof(int32_t)); 210 HILOG_INFO(LOG_CORE, "Read fd:%{public}d str:%{public}s", fd, str.c_str()); 211 struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg); 212 if (cmsg == nullptr) { 213 HILOG_FATAL(LOG_CORE, "Read cmsg is nullptr"); 214 continue; 215 } 216 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS || 217 cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { 218 HILOG_INFO(LOG_CORE, "Read level:%{public}d type:%{public}d len:%{public}d", 219 cmsg->cmsg_level, cmsg->cmsg_type, cmsg->cmsg_len); 220 continue; 221 } 222 int newfd = *(reinterpret_cast<int *>(CMSG_DATA(cmsg))); 223 HILOG_INFO(LOG_CORE, "Read fd:%{public}d newfd:%{public}d str:%{public}s", 224 fd, newfd, str.c_str()); 225 if (cb_) { 226 cb_(newfd, str); 227 } 228 } 229 rc = epoll_ctl(efd, EPOLL_CTL_DEL, cfd_, nullptr); 230 if (rc == -1) { 231 HILOG_WARN(LOG_CORE, "Read epoll_ctl del cfd:%{public}d error:%{public}d", cfd_, errno); 232 } 233 close(cfd_); 234 cfd_ = -1; 235 close(efd); 236} 237 238bool HdcJdwpSimulator::Connect() 239{ 240 while (!disconnectFlag_) { 241 bool b = Connect2Jdwp(); 242 if (!b) { 243 HILOG_INFO(LOG_CORE, "Connect2Jdwp failed cfd:%{public}d", cfd_); 244 WaitForJdwp(); 245 continue; 246 } 247 b = Send2Jdwp(); 248 if (!b) { 249 HILOG_WARN(LOG_CORE, "Send2Jdwp failed cfd:%{public}d", cfd_); 250 continue; 251 } 252 ReadFromJdwp(); 253 } 254 return true; 255} 256 257void HdcJdwpSimulator::WaitForJdwp() 258{ 259 { 260 std::unique_lock<std::mutex> lock(mutex_); 261 cv_.wait(lock, [this]() -> bool { return this->notified_ || this->disconnectFlag_; }); 262 } 263 notified_ = false; 264} 265 266void HdcJdwpSimulator::AddWatchHdcdJdwp() 267{ 268 auto eventCallback = [](const char *key, const char *value, void *context) { 269 auto that = reinterpret_cast<HdcJdwpSimulator *>(context); 270 if (strncmp(key, PERSIST_HDC_JDWP, strlen(PERSIST_HDC_JDWP)) != 0) { 271 return; 272 } 273 if (strncmp(value, "1", strlen("1")) != 0) { 274 return; 275 } 276 that->notified_ = true; 277 that->cv_.notify_one(); 278 }; 279 int rc = WatchParameter(PERSIST_HDC_JDWP, eventCallback, this); 280 HILOG_INFO(LOG_CORE, "AddWatchHdcdJdwp rc:%{public}d", rc); 281} 282 283void HdcJdwpSimulator::DelWatchHdcdJdwp() 284{ 285 int rc = RemoveParameterWatcher(PERSIST_HDC_JDWP, nullptr, nullptr); 286 HILOG_INFO(LOG_CORE, "DelWatchHdcdJdwp rc:%{public}d", rc); 287} 288} // namespace Hdc 289