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
21 namespace Hdc {
22
HdcJdwpSimulator(const std::string processName, const std::string pkgName, bool isDebug, Callback cb)23 HdcJdwpSimulator::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
Disconnect()35 void 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
~HdcJdwpSimulator()46 HdcJdwpSimulator::~HdcJdwpSimulator()
47 {
48 Disconnect();
49 DelWatchHdcdJdwp();
50 }
51
SendBuf(const uint8_t *buf, const int bufLen)52 bool 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
Connect2Jdwp()62 bool 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
Send2Jdwp()104 bool 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
ReadFromJdwp()146 void 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
Connect()238 bool 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
WaitForJdwp()257 void 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
AddWatchHdcdJdwp()266 void 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
DelWatchHdcdJdwp()283 void 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