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