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