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 "devicestatus_msdp_mock.h"
17
18 #include <cerrno>
19 #include <string>
20 #include <unistd.h>
21
22 #include <linux/netlink.h>
23 #include <sys/epoll.h>
24 #include <sys/timerfd.h>
25
26 #include "devicestatus_common.h"
27
28 namespace OHOS {
29 namespace Msdp {
30 namespace DeviceStatus {
31 namespace {
32 constexpr int32_t TIMER_INTERVAL = 3;
33 constexpr int32_t ERR_INVALID_FD = -1;
34 constexpr int32_t ERR_NG = -1;
35 constexpr int32_t TIMER_MS = 1000;
36 DeviceStatusMsdpMock* g_msdpMock = nullptr;
37 } // namespace
38
39 std::vector<int32_t> DeviceStatusMsdpMock::enabledType_ =
40 std::vector<int32_t> (static_cast<int32_t>(DevicestatusDataUtils::DevicestatusType::TYPE_MAX),
41 static_cast<int32_t>(DevicestatusDataUtils::Value::INVALID));
42
Init()43 bool DeviceStatusMsdpMock::Init()
44 {
45 DEV_HILOGD(SERVICE, "DeviceStatusMsdpMock: Enter");
46 if (dataParse_ == nullptr) {
47 dataParse_ = std::make_unique<DeviceStatusDataParse>();
48 }
49 InitMockStore();
50 InitTimer();
51 StartThread();
52 DEV_HILOGD(SERVICE, "DeviceStatusMsdpMock: Exit");
53 return true;
54 }
55
InitMockStore()56 void DeviceStatusMsdpMock::InitMockStore() {}
57
RegisterCallback(std::shared_ptr<MsdpAlgorithmCallback> callback)58 ErrCode DeviceStatusMsdpMock::RegisterCallback(std::shared_ptr<MsdpAlgorithmCallback> callback)
59 {
60 std::lock_guard lock(mutex_);
61 callback_ = callback;
62 return RET_OK;
63 }
64
UnregisterCallback()65 ErrCode DeviceStatusMsdpMock::UnregisterCallback()
66 {
67 std::lock_guard lock(mutex_);
68 callback_ = nullptr;
69 return RET_OK;
70 }
71
Enable(DevicestatusDataUtils::DevicestatusType type)72 ErrCode DeviceStatusMsdpMock::Enable(DevicestatusDataUtils::DevicestatusType type)
73 {
74 DEV_HILOGD(SERVICE, "Enter");
75 if (type < DevicestatusDataUtils::DevicestatusType::TYPE_STILL ||
76 type >= DevicestatusDataUtils::DevicestatusType::TYPE_LID_OPEN) {
77 DEV_HILOGE(SERVICE, "Type error");
78 }
79 enabledType_[type] = static_cast<int32_t>(DevicestatusDataUtils::Value::VALID);
80 Init();
81 DEV_HILOGD(SERVICE, "Exit");
82 return RET_OK;
83 }
84
Disable(DevicestatusDataUtils::DevicestatusType type)85 ErrCode DeviceStatusMsdpMock::Disable(DevicestatusDataUtils::DevicestatusType type)
86 {
87 DEV_HILOGD(SERVICE, "Enter");
88 scFlag_ = false;
89 CloseTimer();
90 DEV_HILOGD(SERVICE, "Exit");
91 return RET_OK;
92 }
93
DisableCount(DevicestatusDataUtils::DevicestatusType type)94 ErrCode DeviceStatusMsdpMock::DisableCount(DevicestatusDataUtils::DevicestatusType type)
95 {
96 DEV_HILOGD(SERVICE, "Enter");
97 enabledType_[type] = static_cast<int32_t>(DevicestatusDataUtils::Value::INVALID);
98 dataParse_->DisableCount(type);
99 DEV_HILOGD(SERVICE, "Exit");
100 return RET_OK;
101 }
102
NotifyMsdpImpl(const DevicestatusDataUtils::DevicestatusData & data)103 ErrCode DeviceStatusMsdpMock::NotifyMsdpImpl(const DevicestatusDataUtils::DevicestatusData& data)
104 {
105 DEV_HILOGD(SERVICE, "Enter");
106 if (g_msdpMock == nullptr) {
107 DEV_HILOGE(SERVICE, "g_msdpMock is nullptr");
108 return ERR_NG;
109 }
110 if (g_msdpMock->GetCallbackImpl() == nullptr) {
111 DEV_HILOGE(SERVICE, "callbacksImpl is nullptr");
112 return ERR_NG;
113 }
114 g_msdpMock->GetCallbackImpl()->OnResult(data);
115
116 return ERR_OK;
117 }
118
InitTimer()119 void DeviceStatusMsdpMock::InitTimer()
120 {
121 DEV_HILOGD(SERVICE, "Enter");
122 epFd_ = epoll_create1(EPOLL_CLOEXEC);
123 if (epFd_ == -1) {
124 DEV_HILOGE(SERVICE, "create epoll fd failed");
125 return;
126 }
127 timerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
128 if (timerFd_ == ERR_INVALID_FD) {
129 DEV_HILOGE(SERVICE, "create timer fd failed");
130 close(epFd_);
131 epFd_ = ERR_INVALID_FD;
132 return;
133 }
134 SetTimerInterval(TIMER_INTERVAL);
135 fcntl(timerFd_, F_SETFL, O_NONBLOCK);
136 callbacks_.insert(std::make_pair(timerFd_, &DeviceStatusMsdpMock::TimerCallback));
137 if (RegisterTimerCallback(timerFd_, EVENT_TIMER_FD)) {
138 DEV_HILOGE(SERVICE, "register timer fd failed");
139 return;
140 }
141 }
142
SetTimerInterval(int32_t interval)143 void DeviceStatusMsdpMock::SetTimerInterval(int32_t interval)
144 {
145 if (timerFd_ == ERR_INVALID_FD) {
146 DEV_HILOGE(SERVICE, "create timer fd failed");
147 return;
148 }
149 if (interval != 0) {
150 timerInterval_ = interval;
151 }
152 if (interval < 0) {
153 interval = 0;
154 }
155 struct itimerspec itval;
156 itval.it_interval.tv_sec = interval;
157 itval.it_interval.tv_nsec = 0;
158 itval.it_value.tv_sec = interval;
159 itval.it_value.tv_nsec = 0;
160 if (timerfd_settime(timerFd_, 0, &itval, nullptr) == -1) {
161 DEV_HILOGE(SERVICE, "set timer failed");
162 return;
163 }
164 }
165
CloseTimer()166 void DeviceStatusMsdpMock::CloseTimer()
167 {
168 DEV_HILOGD(SERVICE, "Enter");
169 close(timerFd_);
170 DEV_HILOGD(SERVICE, "Exit");
171 }
172
TimerCallback()173 void DeviceStatusMsdpMock::TimerCallback()
174 {
175 uint64_t timers;
176 if (read(timerFd_, &timers, sizeof(timers)) == -1) {
177 DEV_HILOGE(SERVICE, "read timer fd failed");
178 return;
179 }
180 GetDeviceStatusData();
181 }
182
GetDeviceStatusData()183 void DeviceStatusMsdpMock::GetDeviceStatusData()
184 {
185 DevicestatusDataUtils::DevicestatusData data;
186 for (int32_t i = int(DevicestatusDataUtils::DevicestatusType::TYPE_STILL);
187 i <= DevicestatusDataUtils::DevicestatusType::TYPE_LID_OPEN; ++i) {
188 if (enabledType_[i] == static_cast<int32_t>(DevicestatusDataUtils::Value::VALID)) {
189 DevicestatusDataUtils::DevicestatusType type = DevicestatusDataUtils::DevicestatusType(i);
190 DEV_HILOGE(SERVICE, "type:%{public}d", type);
191 if (dataParse_ == nullptr) {
192 DEV_HILOGE(SERVICE, "dataParse_ is nullptr");
193 return;
194 }
195 dataParse_->ParseDeviceStatusData(data, type);
196 NotifyMsdpImpl(data);
197 }
198 }
199 }
200
RegisterTimerCallback(const int32_t fd,const EventType et)201 int32_t DeviceStatusMsdpMock::RegisterTimerCallback(const int32_t fd, const EventType et)
202 {
203 DEV_HILOGD(SERVICE, "Enter");
204 struct epoll_event ev;
205 ev.events = EPOLLIN;
206 if (et == EVENT_TIMER_FD) {
207 ev.events |= EPOLLWAKEUP;
208 }
209
210 ev.data.ptr = reinterpret_cast<void*>(this);
211 ev.data.fd = fd;
212 if (epoll_ctl(epFd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
213 DEV_HILOGE(SERVICE, "epoll_ctl failed, error num:%{public}d", errno);
214 return ERR_NG;
215 }
216
217 return ERR_OK;
218 }
219
StartThread()220 void DeviceStatusMsdpMock::StartThread()
221 {
222 DEV_HILOGD(SERVICE, "Enter");
223 std::make_unique<std::thread>(&DeviceStatusMsdpMock::LoopingThreadEntry, this)->detach();
224 }
225
LoopingThreadEntry()226 void DeviceStatusMsdpMock::LoopingThreadEntry()
227 {
228 if (callbacks_.empty()) {
229 DEV_HILOGD(SERVICE, "callbacks_ is empty");
230 return;
231 }
232 size_t cbct = callbacks_.size();
233 struct epoll_event events[cbct];
234 while (alive_) {
235 int32_t nevents = epoll_wait(epFd_, events, cbct, TIMER_INTERVAL * TIMER_MS);
236 if (nevents == -1 || nevents == 0) {
237 continue;
238 }
239 for (int32_t n = 0; n < nevents; ++n) {
240 if (events[n].data.ptr) {
241 DeviceStatusMsdpMock *func = const_cast<DeviceStatusMsdpMock *>(this);
242 (callbacks_.find(events[n].data.fd)->second)(func);
243 }
244 }
245 }
246 }
247
Create(void)248 extern "C" DevicestatusMsdpInterface *Create(void)
249 {
250 DEV_HILOGD(SERVICE, "Enter");
251 g_msdpMock = new DeviceStatusMsdpMock();
252 return g_msdpMock;
253 }
254
Destroy(const DevicestatusMsdpInterface * algorithm)255 extern "C" void Destroy(const DevicestatusMsdpInterface* algorithm)
256 {
257 DEV_HILOGD(SERVICE, "Enter");
258 delete algorithm;
259 }
260 } // namespace DeviceStatus
261 } // namespace Msdp
262 } // namespace OHOS
263