• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 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 "hotplug_detector.h"
17 
18 #include <dirent.h>
19 #include <sys/inotify.h>
20 
21 #include "dfx_hisysevent_device.h"
22 
23 #undef MMI_LOG_DOMAIN
24 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
25 #undef MMI_LOG_TAG
26 #define MMI_LOG_TAG "HotplugDetector"
27 
28 namespace OHOS {
29 namespace MMI {
30 namespace {
31 constexpr auto MAX_EVENT_BUF_SIZE { 512 };
32 constexpr auto INPUT_DEVICES_PATH { "/dev/input/" };
33 
SystemError()34 auto SystemError()
35 {
36     return std::error_code{errno, std::system_category()};
37 }
38 } // namespace
39 
40 HotplugDetector::HotplugDetector() = default;
41 
42 HotplugDetector::~HotplugDetector() = default;
43 
Stop()44 void HotplugDetector::Stop()
45 {
46     CALL_DEBUG_ENTER;
47     inotifyFd_ = {};
48 }
49 
Init(const callback & addFunc,const callback & removeFunc)50 bool HotplugDetector::Init(const callback& addFunc, const callback& removeFunc)
51 {
52     CALL_DEBUG_ENTER;
53     if (!addFunc || !removeFunc) {
54         return false;
55     }
56     addFunc_ = addFunc;
57     removeFunc_ = removeFunc;
58 
59     auto fd = UniqueFd{inotify_init1(IN_CLOEXEC)};
60     if (fd < 0) {
61         auto errMsg = SystemError().message();
62         MMI_HILOGE("Failed to initialize inotify. Error:%{public}s", errMsg.c_str());
63 #ifdef OHOS_BUILD_ENABLE_DFX_RADAR
64         DfxHisyseventDeivce::ReportDeviceFault(DfxHisyseventDeivce::DeviceFaultType::DEVICE_FAULT_TYPE_SYS,
65             "Failed to initialize inotify. Error:" + errMsg);
66 #endif
67         return false;
68     }
69     if (inotify_add_watch(fd, INPUT_DEVICES_PATH, IN_DELETE | IN_CREATE) < 0) {
70         auto errMsg = SystemError().message();
71         MMI_HILOGE("Failed to add watch for input devices. Error:%{public}s", errMsg.c_str());
72 #ifdef OHOS_BUILD_ENABLE_DFX_RADAR
73         DfxHisyseventDeivce::ReportDeviceFault(DfxHisyseventDeivce::DeviceFaultType::DEVICE_FAULT_TYPE_SYS,
74             "Failed to add watch for input devices. Error:" + errMsg);
75 #endif
76         return false;
77     }
78     if (!Scan()) {
79         MMI_HILOGE("Failed to open input devices path");
80         return false;
81     }
82     inotifyFd_ = std::move(fd);
83     return true;
84 }
85 
Scan() const86 bool HotplugDetector::Scan() const
87 {
88     CALL_DEBUG_ENTER;
89     using namespace std::literals::string_literals;
90     auto* dir = opendir(INPUT_DEVICES_PATH);
91     if (dir == nullptr) {
92         auto errMsg = SystemError().message();
93         MMI_HILOGE("Failed to open device input dir. Error:%{public}s", errMsg.c_str());
94 #ifdef OHOS_BUILD_ENABLE_DFX_RADAR
95         DfxHisyseventDeivce::ReportDeviceFault(DfxHisyseventDeivce::DeviceFaultType::DEVICE_FAULT_TYPE_SYS,
96             "Failed to open device input dir. Error:" + errMsg);
97 #endif
98         return false;
99     }
100     dirent* entry = nullptr;
101     while ((entry = readdir(dir)) != nullptr) {
102         if (entry->d_name == "."s || entry->d_name == ".."s) {
103             continue;
104         }
105         addFunc_(std::string{INPUT_DEVICES_PATH} + entry->d_name);
106     }
107     closedir(dir);
108     return true;
109 }
110 
OnEvent() const111 void HotplugDetector::OnEvent() const
112 {
113     constexpr int32_t EVSIZE = static_cast<int32_t>(sizeof(inotify_event));
114     CALL_DEBUG_ENTER;
115     if (inotifyFd_ < 0) {
116         return;
117     }
118     std::byte event_buf[MAX_EVENT_BUF_SIZE];
119     int32_t res = read(inotifyFd_, event_buf, sizeof(event_buf));
120     if (res < EVSIZE) {
121         auto err = SystemError();
122         auto errMsg = err.message();
123         if (err != std::errc::resource_unavailable_try_again) {
124             MMI_HILOGE("Failed to read inotify event. Error:%{public}s", errMsg.c_str());
125 #ifdef OHOS_BUILD_ENABLE_DFX_RADAR
126             DfxHisyseventDeivce::ReportDeviceFault(DfxHisyseventDeivce::DeviceFaultType::DEVICE_FAULT_TYPE_SYS,
127                                                    "Failed to read inotify event. Error:" + errMsg);
128 #endif
129         }
130         return;
131     }
132     inotify_event event;
133     for (int32_t pos = 0; res > EVSIZE;) {
134         std::copy_n(event_buf + pos, sizeof(event), reinterpret_cast<std::byte*>(&event));
135         if (event.len != 0) {
136             auto path = INPUT_DEVICES_PATH + std::string{reinterpret_cast<char*>(event_buf + pos + sizeof(event))};
137             if (event.mask & IN_CREATE) {
138                 addFunc_(path);
139             } else {
140                 removeFunc_(path);
141             }
142         }
143         int32_t consumed = EVSIZE + event.len;
144         pos += consumed;
145         res -= consumed;
146     }
147 }
148 } // namespace MMI
149 } // namespace OHOS
150