• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
18 #include <unistd.h>
19 
20 namespace Hdc {
21 
HdcJdwpSimulator(const std::string processName,const std::string pkgName,bool isDebug,Callback cb)22 HdcJdwpSimulator::HdcJdwpSimulator(const std::string processName, const std::string pkgName, bool isDebug, Callback cb)
23 {
24     processName_ = processName;
25     pkgName_ = pkgName;
26     isDebug_ = isDebug;
27     cb_ = cb;
28     cfd_ = -1;
29     ctxPoint_ = static_cast<HCtxJdwpSimulator>(MallocContext());
30     disconnectFlag_ = false;
31     startOnce_ = true;
32 }
33 
Disconnect()34 void HdcJdwpSimulator::Disconnect()
35 {
36     disconnectFlag_ = true;
37     if (ctxPoint_ != nullptr && ctxPoint_->cfd > -1) {
38         shutdown(ctxPoint_->cfd, SHUT_RDWR);
39         close(ctxPoint_->cfd);
40         ctxPoint_->cfd = -1;
41     }
42     if (readThread_.joinable()) {
43         readThread_.join();
44     }
45 }
46 
~HdcJdwpSimulator()47 HdcJdwpSimulator::~HdcJdwpSimulator()
48 {
49     disconnectFlag_ = true;
50     if (ctxPoint_ != nullptr && ctxPoint_->cfd > -1) {
51         shutdown(ctxPoint_->cfd, SHUT_RDWR);
52         close(ctxPoint_->cfd);
53         ctxPoint_->cfd = -1;
54     }
55     if (readThread_.joinable()) {
56         readThread_.join();
57     }
58     if (ctxPoint_ != nullptr) {
59         delete ctxPoint_;
60         ctxPoint_ = nullptr;
61     }
62 }
63 
SendToJpid(int fd,const uint8_t * buf,const int bufLen)64 bool HdcJdwpSimulator::SendToJpid(int fd, const uint8_t *buf, const int bufLen)
65 {
66     ssize_t rc = write(fd, buf, bufLen);
67     if (rc < 0) {
68         OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "SendToJpid failed errno:%{public}d", errno);
69         return false;
70     }
71     return true;
72 }
73 
ConnectJpid(HdcJdwpSimulator * param)74 bool HdcJdwpSimulator::ConnectJpid(HdcJdwpSimulator *param)
75 {
76     uint32_t pidCurr = static_cast<uint32_t>(getpid());
77     HdcJdwpSimulator *thisClass = param;
78 #ifdef JS_JDWP_CONNECT
79     std::string processName = thisClass->processName_;
80     std::string pkgName = thisClass->pkgName_;
81     bool isDebug = thisClass->isDebug_;
82     std::string pp = pkgName;
83     if (!processName.empty()) {
84         pp += "/" + processName;
85     }
86     uint32_t ppSize = pp.size() + sizeof(JsMsgHeader);
87     uint8_t* info = new (std::nothrow) uint8_t[ppSize]();
88     if (info == nullptr) {
89         OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "ConnectJpid new info fail.");
90         return false;
91     }
92     if (memset_s(info, ppSize, 0, ppSize) != EOK) {
93         delete[] info;
94         info = nullptr;
95         return false;
96     }
97     JsMsgHeader *jsMsg = reinterpret_cast<JsMsgHeader *>(info);
98     jsMsg->msgLen = ppSize;
99     jsMsg->pid = pidCurr;
100     jsMsg->isDebug = isDebug;
101     OHOS::HiviewDFX::HiLog::Info(LOG_LABEL,
102         "ConnectJpid send pid:%{public}d, pp:%{public}s, isDebug:%{public}d, msglen:%{public}d",
103         jsMsg->pid, pp.c_str(), isDebug, jsMsg->msgLen);
104     bool ret = true;
105     if (memcpy_s(info + sizeof(JsMsgHeader), pp.size(), &pp[0], pp.size()) != EOK) {
106         OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "ConnectJpid memcpy_s fail :%{public}s.", pp.c_str());
107         ret = false;
108     } else {
109         ret = SendToJpid(thisClass->ctxPoint_->cfd, static_cast<uint8_t*>(info), ppSize);
110     }
111     delete[] info;
112     return ret;
113 #endif
114     return false;
115 }
116 
MallocContext()117 void *HdcJdwpSimulator::MallocContext()
118 {
119     HCtxJdwpSimulator ctx = nullptr;
120     if ((ctx = new (std::nothrow) ContextJdwpSimulator()) == nullptr) {
121         return nullptr;
122     }
123     ctx->thisClass = this;
124     ctx->cfd = -1;
125     return ctx;
126 }
127 
Connect()128 bool HdcJdwpSimulator::Connect()
129 {
130     const char jdwp[] = { '\0', 'o', 'h', 'j', 'p', 'i', 'd', '-', 'c', 'o', 'n', 't', 'r', 'o', 'l', 0 };
131     if (ctxPoint_ == nullptr) {
132         OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "MallocContext failed");
133         return false;
134     }
135     struct sockaddr_un caddr;
136     if (memset_s(&caddr, sizeof(caddr), 0, sizeof(caddr)) != EOK) {
137         OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "memset_s failed");
138         return false;
139     }
140     caddr.sun_family = AF_UNIX;
141     for (size_t i = 0; i < sizeof(jdwp); i++) {
142         caddr.sun_path[i] = jdwp[i];
143     }
144     cfd_ = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
145     if (cfd_ < 0) {
146         OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "socket failed errno:%{public}d", errno);
147         return false;
148     }
149     ctxPoint_->cfd = cfd_;
150 
151     struct timeval timeout;
152     timeout.tv_sec = 1;
153     timeout.tv_usec = 0;
154     setsockopt(cfd_, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));
155     size_t caddrLen = sizeof(caddr.sun_family) + sizeof(jdwp) - 1;
156     int rc = connect(cfd_, reinterpret_cast<struct sockaddr *>(&caddr), caddrLen);
157     if (rc != 0) {
158         OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "connect failed errno:%{public}d", errno);
159         close(cfd_);
160         cfd_ = -1;
161         return false;
162     }
163     if (ConnectJpid(this)) {
164         if (startOnce_) {
165             startOnce_ = false;
166             ReadStart();
167         }
168     }
169     return true;
170 }
171 
ReadStart()172 void HdcJdwpSimulator::ReadStart()
173 {
174     readThread_ = std::thread(ReadWork, this);
175 }
176 
ReadWork(HdcJdwpSimulator * param)177 void HdcJdwpSimulator::ReadWork(HdcJdwpSimulator *param)
178 {
179     HdcJdwpSimulator *jdwp = param;
180     jdwp->Read();
181 }
182 
Read()183 void HdcJdwpSimulator::Read()
184 {
185     constexpr size_t size = 256;
186     constexpr long sec = 5;
187     uint8_t buf[size] = { 0 };
188     while (!disconnectFlag_ && cfd_ > -1) {
189         ssize_t cnt = 0;
190         ssize_t minlen = sizeof(int32_t);
191         fd_set rset;
192         struct timeval timeout;
193         timeout.tv_sec = sec;
194         timeout.tv_usec = 0;
195         FD_ZERO(&rset);
196         FD_SET(cfd_, &rset);
197         int rc = select(cfd_ + 1, &rset, nullptr, nullptr, &timeout);
198         if (rc < 0) {
199             if (errno == EINTR) {
200                 continue;
201             }
202             OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "Read select fd:%{public}d error:%{public}d", cfd_, errno);
203             break;
204         } else if (rc == 0) {
205             continue;
206         }
207         if (memset_s(buf, size, 0, size) != EOK) {
208             continue;
209         }
210         struct iovec iov;
211         iov.iov_base = buf;
212         iov.iov_len = size - 1;
213         struct msghdr msg;
214         msg.msg_iov = &iov;
215         msg.msg_iovlen = 1;
216         int len = CMSG_SPACE(static_cast<unsigned int>(sizeof(int)));
217         char ctlBuf[len];
218         msg.msg_controllen = sizeof(ctlBuf);
219         msg.msg_control = ctlBuf;
220         cnt = recvmsg(cfd_, &msg, 0);
221         if (cnt < 0) {
222             OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "Read recvmsg cfd:%{public}d errno:%{public}d", cfd_, errno);
223             break;
224         } else if (cnt == 0) {
225             OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, "Read recvmsg socket peer closed cfd:%{public}d", cfd_);
226             close(cfd_);
227             cfd_ = -1;
228             Reconnect();
229             continue;
230         } else if (cnt < minlen) {
231             OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, "Read recvmsg cnt:%{public}zd cfd:%{public}d", cnt, cfd_);
232             continue;
233         }
234         int32_t fd = *reinterpret_cast<int32_t *>(buf);
235         std::string str(reinterpret_cast<char *>(buf + sizeof(int32_t)), cnt - sizeof(int32_t));
236         OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "Read fd:%{public}d str:%{public}s", fd, str.c_str());
237         struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
238         if (cmsg == nullptr) {
239             OHOS::HiviewDFX::HiLog::Fatal(LOG_LABEL, "Read cmsg is nullptr");
240             continue;
241         }
242         if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS ||
243             cmsg->cmsg_len != CMSG_LEN(sizeof(int))) {
244             OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "Read level:%{public}d type:%{public}d len:%{public}d",
245                 cmsg->cmsg_level, cmsg->cmsg_type, cmsg->cmsg_len);
246             continue;
247         }
248         int newfd = *(reinterpret_cast<int *>(CMSG_DATA(cmsg)));
249         OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "Read fd:%{public}d newfd:%{public}d str:%{public}s",
250             fd, newfd, str.c_str());
251         if (cb_) {
252             cb_(newfd, str);
253         }
254     }
255 }
256 
Reconnect()257 void HdcJdwpSimulator::Reconnect()
258 {
259     constexpr int timeout = 3;
260     int retry = 5;
261     // wait for hdcd restart
262     sleep(timeout);
263     while (!disconnectFlag_ && retry > 0) {
264         bool c = Connect();
265         if (c) {
266             OHOS::HiviewDFX::HiLog::Info(LOG_LABEL, "Reconnect success cfd:%{public}d", cfd_);
267             break;
268         }
269         OHOS::HiviewDFX::HiLog::Warn(LOG_LABEL, "Reconnect cfd:%{public}d retry:%{public}d", cfd_, retry--);
270         sleep(timeout);
271     }
272 }
273 } // namespace Hdc
274