1 /*
2  * Copyright (c) 2022-2023 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 "monitor.h"
17 
18 #include <cstring>
19 #include <string_view>
20 
21 #include <sys/epoll.h>
22 #include <unistd.h>
23 
24 #include "devicestatus_define.h"
25 #include "fi_log.h"
26 #include "napi_constants.h"
27 #include "utility.h"
28 
29 #undef LOG_TAG
30 #define LOG_TAG "Monitor"
31 
32 namespace OHOS {
33 namespace Msdp {
34 namespace DeviceStatus {
35 
~Monitor()36 Monitor::~Monitor()
37 {
38     Disable();
39 }
40 
Dispatch(const struct epoll_event & ev)41 void Monitor::Dispatch(const struct epoll_event &ev)
42 {
43     if ((ev.events & EPOLLIN) == EPOLLIN) {
44         ReceiveDevice();
45     } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
46         FI_HILOGE("Epoll hangup, errno:%{public}s", strerror(errno));
47     }
48 }
49 
SetDeviceMgr(IDeviceMgr * devMgr)50 void Monitor::SetDeviceMgr(IDeviceMgr *devMgr)
51 {
52     CALL_DEBUG_ENTER;
53     CHKPV(devMgr);
54     devMgr_ = devMgr;
55 }
56 
Enable()57 int32_t Monitor::Enable()
58 {
59     CALL_INFO_TRACE;
60     int32_t ret = OpenConnection();
61     if (ret == RET_OK) {
62         ret = EnableReceiving();
63         if (ret != RET_OK) {
64             FI_HILOGE("Enable receive failed");
65             Disable();
66         }
67     }
68     return ret;
69 }
70 
Disable()71 void Monitor::Disable()
72 {
73     CALL_INFO_TRACE;
74     if (devWd_ >= 0) {
75         int32_t ret = inotify_rm_watch(inotifyFd_, devWd_);
76         if (ret != 0) {
77             FI_HILOGE("inotify_rm_watch failed");
78         }
79         devWd_ = -1;
80     }
81     if (inotifyFd_ >= 0) {
82         if (close(inotifyFd_) < 0) {
83             FI_HILOGE("close inotify fd failed, error:%{public}s, inotifyFd_:%{public}d", strerror(errno), inotifyFd_);
84         }
85         inotifyFd_ = -1;
86     }
87 }
88 
OpenConnection()89 int32_t Monitor::OpenConnection()
90 {
91     CALL_DEBUG_ENTER;
92     inotifyFd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
93     if (inotifyFd_ < 0) {
94         FI_HILOGE("Initializing inotify, errno:%{public}s", strerror(errno));
95         return RET_ERR;
96     }
97     return RET_OK;
98 }
99 
EnableReceiving()100 int32_t Monitor::EnableReceiving()
101 {
102     CALL_DEBUG_ENTER;
103     devWd_ = inotify_add_watch(inotifyFd_, DEV_INPUT_PATH.c_str(), IN_CREATE | IN_DELETE);
104     if (devWd_ < 0) {
105         FI_HILOGE("Watching (\'%{public}s\') failed, errno:%{public}s", DEV_INPUT_PATH.c_str(), strerror(errno));
106         return RET_ERR;
107     }
108     return RET_OK;
109 }
110 
ReceiveDevice()111 void Monitor::ReceiveDevice()
112 {
113     CALL_DEBUG_ENTER;
114     char buf[sizeof(struct inotify_event) + NAME_MAX + 1];
115     size_t bufSize { sizeof(struct inotify_event) };
116     ssize_t numRead { 0 };
117 
118     do {
119         bufSize += sizeof(struct inotify_event);
120         numRead = ::read(inotifyFd_, buf, bufSize);
121     } while ((numRead < 0) && (errno == EINVAL) &&
122              (bufSize + sizeof(struct inotify_event) <= sizeof(buf)));
123 
124     if (numRead < 0) {
125         FI_HILOGE("Reading failed, errno:%{public}s", strerror(errno));
126         return;
127     }
128     if (numRead == 0) {
129         FI_HILOGW("End of file encountered");
130         return;
131     }
132     FI_HILOGD("Read %{public}zd bytes from inotify events", numRead);
133     for (char *p = buf; p < buf + numRead;) {
134         struct inotify_event *event = reinterpret_cast<struct inotify_event *>(p);
135         HandleInotifyEvent(event);
136         p += sizeof(struct inotify_event) + event->len;
137     }
138 }
139 
HandleInotifyEvent(struct inotify_event * event) const140 void Monitor::HandleInotifyEvent(struct inotify_event *event) const
141 {
142     CALL_DEBUG_ENTER;
143     CHKPV(event);
144     if (Utility::IsEmpty(event->name)) {
145         return;
146     }
147     std::string devNode { event->name };
148 
149     if ((event->mask & IN_CREATE) == IN_CREATE) {
150         AddDevice(devNode);
151     } else if ((event->mask & IN_DELETE) == IN_DELETE) {
152         RemoveDevice(devNode);
153     }
154 }
155 
AddDevice(const std::string & devNode) const156 void Monitor::AddDevice(const std::string &devNode) const
157 {
158     CALL_DEBUG_ENTER;
159     CHKPV(devMgr_);
160     devMgr_->AddDevice(devNode);
161 }
162 
RemoveDevice(const std::string & devNode) const163 void Monitor::RemoveDevice(const std::string &devNode) const
164 {
165     CALL_DEBUG_ENTER;
166     CHKPV(devMgr_);
167     devMgr_->RemoveDevice(devNode);
168 }
169 } // namespace DeviceStatus
170 } // namespace Msdp
171 } // namespace OHOS