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