1c29fa5a6Sopenharmony_ci/*
2c29fa5a6Sopenharmony_ci * Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3c29fa5a6Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4c29fa5a6Sopenharmony_ci * you may not use this file except in compliance with the License.
5c29fa5a6Sopenharmony_ci * You may obtain a copy of the License at
6c29fa5a6Sopenharmony_ci *
7c29fa5a6Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8c29fa5a6Sopenharmony_ci *
9c29fa5a6Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10c29fa5a6Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11c29fa5a6Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12c29fa5a6Sopenharmony_ci * See the License for the specific language governing permissions and
13c29fa5a6Sopenharmony_ci * limitations under the License.
14c29fa5a6Sopenharmony_ci */
15c29fa5a6Sopenharmony_ci
16c29fa5a6Sopenharmony_ci#include "monitor.h"
17c29fa5a6Sopenharmony_ci
18c29fa5a6Sopenharmony_ci#include <cstring>
19c29fa5a6Sopenharmony_ci#include <string_view>
20c29fa5a6Sopenharmony_ci
21c29fa5a6Sopenharmony_ci#include <sys/epoll.h>
22c29fa5a6Sopenharmony_ci#include <unistd.h>
23c29fa5a6Sopenharmony_ci
24c29fa5a6Sopenharmony_ci#include "devicestatus_define.h"
25c29fa5a6Sopenharmony_ci#include "fi_log.h"
26c29fa5a6Sopenharmony_ci#include "napi_constants.h"
27c29fa5a6Sopenharmony_ci#include "utility.h"
28c29fa5a6Sopenharmony_ci
29c29fa5a6Sopenharmony_ci#undef LOG_TAG
30c29fa5a6Sopenharmony_ci#define LOG_TAG "Monitor"
31c29fa5a6Sopenharmony_ci
32c29fa5a6Sopenharmony_cinamespace OHOS {
33c29fa5a6Sopenharmony_cinamespace Msdp {
34c29fa5a6Sopenharmony_cinamespace DeviceStatus {
35c29fa5a6Sopenharmony_ci
36c29fa5a6Sopenharmony_ciMonitor::~Monitor()
37c29fa5a6Sopenharmony_ci{
38c29fa5a6Sopenharmony_ci    Disable();
39c29fa5a6Sopenharmony_ci}
40c29fa5a6Sopenharmony_ci
41c29fa5a6Sopenharmony_civoid Monitor::Dispatch(const struct epoll_event &ev)
42c29fa5a6Sopenharmony_ci{
43c29fa5a6Sopenharmony_ci    if ((ev.events & EPOLLIN) == EPOLLIN) {
44c29fa5a6Sopenharmony_ci        ReceiveDevice();
45c29fa5a6Sopenharmony_ci    } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
46c29fa5a6Sopenharmony_ci        FI_HILOGE("Epoll hangup, errno:%{public}s", strerror(errno));
47c29fa5a6Sopenharmony_ci    }
48c29fa5a6Sopenharmony_ci}
49c29fa5a6Sopenharmony_ci
50c29fa5a6Sopenharmony_civoid Monitor::SetDeviceMgr(IDeviceMgr *devMgr)
51c29fa5a6Sopenharmony_ci{
52c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
53c29fa5a6Sopenharmony_ci    CHKPV(devMgr);
54c29fa5a6Sopenharmony_ci    devMgr_ = devMgr;
55c29fa5a6Sopenharmony_ci}
56c29fa5a6Sopenharmony_ci
57c29fa5a6Sopenharmony_ciint32_t Monitor::Enable()
58c29fa5a6Sopenharmony_ci{
59c29fa5a6Sopenharmony_ci    CALL_INFO_TRACE;
60c29fa5a6Sopenharmony_ci    int32_t ret = OpenConnection();
61c29fa5a6Sopenharmony_ci    if (ret == RET_OK) {
62c29fa5a6Sopenharmony_ci        ret = EnableReceiving();
63c29fa5a6Sopenharmony_ci        if (ret != RET_OK) {
64c29fa5a6Sopenharmony_ci            FI_HILOGE("Enable receive failed");
65c29fa5a6Sopenharmony_ci            Disable();
66c29fa5a6Sopenharmony_ci        }
67c29fa5a6Sopenharmony_ci    }
68c29fa5a6Sopenharmony_ci    return ret;
69c29fa5a6Sopenharmony_ci}
70c29fa5a6Sopenharmony_ci
71c29fa5a6Sopenharmony_civoid Monitor::Disable()
72c29fa5a6Sopenharmony_ci{
73c29fa5a6Sopenharmony_ci    CALL_INFO_TRACE;
74c29fa5a6Sopenharmony_ci    if (devWd_ >= 0) {
75c29fa5a6Sopenharmony_ci        int32_t ret = inotify_rm_watch(inotifyFd_, devWd_);
76c29fa5a6Sopenharmony_ci        if (ret != 0) {
77c29fa5a6Sopenharmony_ci            FI_HILOGE("inotify_rm_watch failed");
78c29fa5a6Sopenharmony_ci        }
79c29fa5a6Sopenharmony_ci        devWd_ = -1;
80c29fa5a6Sopenharmony_ci    }
81c29fa5a6Sopenharmony_ci    if (inotifyFd_ >= 0) {
82c29fa5a6Sopenharmony_ci        if (close(inotifyFd_) < 0) {
83c29fa5a6Sopenharmony_ci            FI_HILOGE("close inotify fd failed, error:%{public}s, inotifyFd_:%{public}d", strerror(errno), inotifyFd_);
84c29fa5a6Sopenharmony_ci        }
85c29fa5a6Sopenharmony_ci        inotifyFd_ = -1;
86c29fa5a6Sopenharmony_ci    }
87c29fa5a6Sopenharmony_ci}
88c29fa5a6Sopenharmony_ci
89c29fa5a6Sopenharmony_ciint32_t Monitor::OpenConnection()
90c29fa5a6Sopenharmony_ci{
91c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
92c29fa5a6Sopenharmony_ci    inotifyFd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
93c29fa5a6Sopenharmony_ci    if (inotifyFd_ < 0) {
94c29fa5a6Sopenharmony_ci        FI_HILOGE("Initializing inotify, errno:%{public}s", strerror(errno));
95c29fa5a6Sopenharmony_ci        return RET_ERR;
96c29fa5a6Sopenharmony_ci    }
97c29fa5a6Sopenharmony_ci    return RET_OK;
98c29fa5a6Sopenharmony_ci}
99c29fa5a6Sopenharmony_ci
100c29fa5a6Sopenharmony_ciint32_t Monitor::EnableReceiving()
101c29fa5a6Sopenharmony_ci{
102c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
103c29fa5a6Sopenharmony_ci    devWd_ = inotify_add_watch(inotifyFd_, DEV_INPUT_PATH.c_str(), IN_CREATE | IN_DELETE);
104c29fa5a6Sopenharmony_ci    if (devWd_ < 0) {
105c29fa5a6Sopenharmony_ci        FI_HILOGE("Watching (\'%{public}s\') failed, errno:%{public}s", DEV_INPUT_PATH.c_str(), strerror(errno));
106c29fa5a6Sopenharmony_ci        return RET_ERR;
107c29fa5a6Sopenharmony_ci    }
108c29fa5a6Sopenharmony_ci    return RET_OK;
109c29fa5a6Sopenharmony_ci}
110c29fa5a6Sopenharmony_ci
111c29fa5a6Sopenharmony_civoid Monitor::ReceiveDevice()
112c29fa5a6Sopenharmony_ci{
113c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
114c29fa5a6Sopenharmony_ci    char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
115c29fa5a6Sopenharmony_ci    size_t bufSize { sizeof(struct inotify_event) };
116c29fa5a6Sopenharmony_ci    ssize_t numRead { 0 };
117c29fa5a6Sopenharmony_ci
118c29fa5a6Sopenharmony_ci    do {
119c29fa5a6Sopenharmony_ci        bufSize += sizeof(struct inotify_event);
120c29fa5a6Sopenharmony_ci        numRead = ::read(inotifyFd_, buf, bufSize);
121c29fa5a6Sopenharmony_ci    } while ((numRead < 0) && (errno == EINVAL) &&
122c29fa5a6Sopenharmony_ci             (bufSize + sizeof(struct inotify_event) <= sizeof(buf)));
123c29fa5a6Sopenharmony_ci
124c29fa5a6Sopenharmony_ci    if (numRead < 0) {
125c29fa5a6Sopenharmony_ci        FI_HILOGE("Reading failed, errno:%{public}s", strerror(errno));
126c29fa5a6Sopenharmony_ci        return;
127c29fa5a6Sopenharmony_ci    }
128c29fa5a6Sopenharmony_ci    if (numRead == 0) {
129c29fa5a6Sopenharmony_ci        FI_HILOGW("End of file encountered");
130c29fa5a6Sopenharmony_ci        return;
131c29fa5a6Sopenharmony_ci    }
132c29fa5a6Sopenharmony_ci    FI_HILOGD("Read %{public}zd bytes from inotify events", numRead);
133c29fa5a6Sopenharmony_ci    for (char *p = buf; p < buf + numRead;) {
134c29fa5a6Sopenharmony_ci        struct inotify_event *event = reinterpret_cast<struct inotify_event *>(p);
135c29fa5a6Sopenharmony_ci        HandleInotifyEvent(event);
136c29fa5a6Sopenharmony_ci        p += sizeof(struct inotify_event) + event->len;
137c29fa5a6Sopenharmony_ci    }
138c29fa5a6Sopenharmony_ci}
139c29fa5a6Sopenharmony_ci
140c29fa5a6Sopenharmony_civoid Monitor::HandleInotifyEvent(struct inotify_event *event) const
141c29fa5a6Sopenharmony_ci{
142c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
143c29fa5a6Sopenharmony_ci    CHKPV(event);
144c29fa5a6Sopenharmony_ci    if (Utility::IsEmpty(event->name)) {
145c29fa5a6Sopenharmony_ci        return;
146c29fa5a6Sopenharmony_ci    }
147c29fa5a6Sopenharmony_ci    std::string devNode { event->name };
148c29fa5a6Sopenharmony_ci
149c29fa5a6Sopenharmony_ci    if ((event->mask & IN_CREATE) == IN_CREATE) {
150c29fa5a6Sopenharmony_ci        AddDevice(devNode);
151c29fa5a6Sopenharmony_ci    } else if ((event->mask & IN_DELETE) == IN_DELETE) {
152c29fa5a6Sopenharmony_ci        RemoveDevice(devNode);
153c29fa5a6Sopenharmony_ci    }
154c29fa5a6Sopenharmony_ci}
155c29fa5a6Sopenharmony_ci
156c29fa5a6Sopenharmony_civoid Monitor::AddDevice(const std::string &devNode) const
157c29fa5a6Sopenharmony_ci{
158c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
159c29fa5a6Sopenharmony_ci    CHKPV(devMgr_);
160c29fa5a6Sopenharmony_ci    devMgr_->AddDevice(devNode);
161c29fa5a6Sopenharmony_ci}
162c29fa5a6Sopenharmony_ci
163c29fa5a6Sopenharmony_civoid Monitor::RemoveDevice(const std::string &devNode) const
164c29fa5a6Sopenharmony_ci{
165c29fa5a6Sopenharmony_ci    CALL_DEBUG_ENTER;
166c29fa5a6Sopenharmony_ci    CHKPV(devMgr_);
167c29fa5a6Sopenharmony_ci    devMgr_->RemoveDevice(devNode);
168c29fa5a6Sopenharmony_ci}
169c29fa5a6Sopenharmony_ci} // namespace DeviceStatus
170c29fa5a6Sopenharmony_ci} // namespace Msdp
171c29fa5a6Sopenharmony_ci} // namespace OHOS