xref: /developtools/hdc/src/register/hdc_jdwp.cpp (revision cc290419)
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