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 <sys/epoll.h>
23 #include <sys/timerfd.h>
24
25 #include "devicestatus_common.h"
26 #include "devicestatus_define.h"
27 #include "fi_log.h"
28
29 #undef LOG_TAG
30 #define LOG_TAG "DeviceStatusMsdpMock"
31
32 namespace OHOS {
33 namespace Msdp {
34 namespace DeviceStatus {
35 namespace {
36 constexpr int32_t TIMER_INTERVAL { 3 };
37 constexpr int32_t ERR_INVALID_FD { -1 };
38 DeviceStatusMsdpMock* g_msdpMock { nullptr };
39 } // namespace
40
DeviceStatusMsdpMock()41 DeviceStatusMsdpMock::DeviceStatusMsdpMock()
42 {
43 enabledType_ = {
44 TYPE_STILL,
45 TYPE_RELATIVE_STILL,
46 TYPE_CAR_BLUETOOTH
47 };
48 if (dataParse_ == nullptr) {
49 dataParse_ = std::make_unique<DeviceStatusDataParse>();
50 }
51 }
52
~DeviceStatusMsdpMock()53 DeviceStatusMsdpMock::~DeviceStatusMsdpMock()
54 {
55 callbacks_.clear();
56 alive_ = false;
57 CloseTimer();
58 if (thread_.joinable()) {
59 thread_.join();
60 FI_HILOGI("thread_ is stop");
61 }
62 }
63
Init()64 bool DeviceStatusMsdpMock::Init()
65 {
66 CALL_DEBUG_ENTER;
67 InitTimer();
68 StartThread();
69 return true;
70 }
71
RegisterCallback(std::shared_ptr<MsdpAlgoCallback> callback)72 ErrCode DeviceStatusMsdpMock::RegisterCallback(std::shared_ptr<MsdpAlgoCallback> callback)
73 {
74 std::lock_guard lock(mutex_);
75 callback_ = callback;
76 return RET_OK;
77 }
78
UnregisterCallback()79 ErrCode DeviceStatusMsdpMock::UnregisterCallback()
80 {
81 std::lock_guard lock(mutex_);
82 callback_ = nullptr;
83 return RET_OK;
84 }
85
Enable(Type type)86 ErrCode DeviceStatusMsdpMock::Enable(Type type)
87 {
88 CALL_DEBUG_ENTER;
89 Init();
90 return RET_OK;
91 }
92
Disable(Type type)93 ErrCode DeviceStatusMsdpMock::Disable(Type type)
94 {
95 CALL_DEBUG_ENTER;
96 alive_ = false;
97 CloseTimer();
98 if (thread_.joinable()) {
99 thread_.join();
100 FI_HILOGI("thread_ is stop");
101 }
102 return RET_OK;
103 }
104
DisableCount(Type type)105 ErrCode DeviceStatusMsdpMock::DisableCount(Type type)
106 {
107 CALL_DEBUG_ENTER;
108 CHKPR(dataParse_, RET_ERR);
109 dataParse_->DisableCount(type);
110 return RET_OK;
111 }
112
NotifyMsdpImpl(const Data & data)113 ErrCode DeviceStatusMsdpMock::NotifyMsdpImpl(const Data &data)
114 {
115 CALL_DEBUG_ENTER;
116 CHKPR(g_msdpMock, RET_ERR);
117 CHKPR(g_msdpMock->GetCallbackImpl(), RET_ERR);
118 FI_HILOGI("type:%{public}d, value:%{public}d", data.type, data.value);
119 g_msdpMock->GetCallbackImpl()->OnResult(data);
120 return RET_OK;
121 }
122
InitTimer()123 void DeviceStatusMsdpMock::InitTimer()
124 {
125 CALL_DEBUG_ENTER;
126 epFd_ = epoll_create1(EPOLL_CLOEXEC);
127 if (epFd_ == -1) {
128 FI_HILOGE("Create epoll fd failed");
129 return;
130 }
131 timerFd_ = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK);
132 if (timerFd_ == ERR_INVALID_FD) {
133 FI_HILOGE("Create timer fd failed");
134 if (close(epFd_) < 0) {
135 FI_HILOGE("Close epoll fd failed, error:%{public}s, epFd_:%{public}d", strerror(errno), epFd_);
136 }
137 epFd_ = ERR_INVALID_FD;
138 return;
139 }
140 SetTimerInterval(TIMER_INTERVAL);
141 fcntl(timerFd_, F_SETFL, O_NONBLOCK);
142 auto [_, ret] = callbacks_.insert(std::make_pair(timerFd_, &DeviceStatusMsdpMock::TimerCallback));
143 if (!ret) {
144 FI_HILOGW("Insert timer fd failed");
145 }
146 if (RegisterTimerCallback(timerFd_, EVENT_TIMER_FD)) {
147 FI_HILOGE("Register timer fd failed");
148 return;
149 }
150 }
151
SetTimerInterval(int32_t interval)152 int32_t DeviceStatusMsdpMock::SetTimerInterval(int32_t interval)
153 {
154 if (timerFd_ == ERR_INVALID_FD) {
155 FI_HILOGE("Create timer fd failed");
156 return RET_ERR;
157 }
158
159 if (interval < 0) {
160 FI_HILOGE("Illegal time interval");
161 return RET_ERR;
162 }
163 struct itimerspec itval;
164 itval.it_interval.tv_sec = interval;
165 itval.it_interval.tv_nsec = 0;
166 itval.it_value.tv_sec = interval;
167 itval.it_value.tv_nsec = 0;
168 if (timerfd_settime(timerFd_, 0, &itval, nullptr) == -1) {
169 FI_HILOGE("Set timer failed");
170 return RET_ERR;
171 }
172 return RET_OK;
173 }
174
CloseTimer()175 void DeviceStatusMsdpMock::CloseTimer()
176 {
177 if (timerFd_ < 0) {
178 FI_HILOGE("Invalid timerFd_");
179 return;
180 }
181 if (close(timerFd_) < 0) {
182 FI_HILOGE("Close timer fd failed, error:%{public}s, timerFd_:%{public}d", strerror(errno), timerFd_);
183 }
184 timerFd_ = -1;
185 }
186
TimerCallback()187 void DeviceStatusMsdpMock::TimerCallback()
188 {
189 uint64_t timers {};
190 if (read(timerFd_, &timers, sizeof(timers)) == -1) {
191 FI_HILOGE("Read timer fd failed");
192 return;
193 }
194 GetDeviceStatusData();
195 }
196
GetDeviceStatusData()197 int32_t DeviceStatusMsdpMock::GetDeviceStatusData()
198 {
199 for (const auto &item : enabledType_) {
200 Type type = item;
201 CHKPR(dataParse_, RET_ERR);
202 Data data;
203 dataParse_->ParseDeviceStatusData(type, data);
204 FI_HILOGD("Mock type:%{public}d, value:%{public}d", data.type, data.value);
205 NotifyMsdpImpl(data);
206 }
207 return RET_OK;
208 }
209
RegisterTimerCallback(int32_t fd,const EventType et)210 int32_t DeviceStatusMsdpMock::RegisterTimerCallback(int32_t fd, const EventType et)
211 {
212 CALL_DEBUG_ENTER;
213 struct epoll_event ev;
214 ev.events = EPOLLIN;
215 if (et == EVENT_TIMER_FD) {
216 ev.events |= EPOLLWAKEUP;
217 }
218
219 ev.data.ptr = reinterpret_cast<void*>(this);
220 ev.data.fd = fd;
221 if (epoll_ctl(epFd_, EPOLL_CTL_ADD, fd, &ev) == -1) {
222 FI_HILOGE("epoll_ctl failed, errno:%{public}d", errno);
223 return RET_ERR;
224 }
225
226 return RET_OK;
227 }
228
StartThread()229 void DeviceStatusMsdpMock::StartThread()
230 {
231 CALL_DEBUG_ENTER;
232 if (!alive_) {
233 alive_ = true;
234 thread_ = std::thread([this] { this->LoopingThreadEntry(); });
235 }
236 }
237
LoopingThreadEntry()238 void DeviceStatusMsdpMock::LoopingThreadEntry()
239 {
240 SetThreadName("os_loop_mock");
241 if (callbacks_.empty()) {
242 FI_HILOGD("callbacks_ is empty");
243 return;
244 }
245 size_t cbct = callbacks_.size();
246 struct epoll_event events[cbct];
247 while (alive_) {
248 int32_t timeout = 200;
249 int32_t nevents = epoll_wait(epFd_, events, cbct, timeout);
250 if (nevents == -1) {
251 FI_HILOGE("No events available");
252 return;
253 }
254 for (int32_t n = 0; n < nevents; ++n) {
255 if (events[n].data.ptr) {
256 DeviceStatusMsdpMock *func = const_cast<DeviceStatusMsdpMock *>(this);
257 (callbacks_.find(events[n].data.fd)->second)(func);
258 }
259 }
260 }
261 }
262
Create(void)263 extern "C" IMsdp *Create(void)
264 {
265 CALL_DEBUG_ENTER;
266 g_msdpMock = new (std::nothrow) DeviceStatusMsdpMock();
267 CHKPP(g_msdpMock);
268 return g_msdpMock;
269 }
270
Destroy(const IMsdp * algorithm)271 extern "C" void Destroy(const IMsdp* algorithm)
272 {
273 CALL_INFO_TRACE;
274 if (algorithm != nullptr) {
275 FI_HILOGD("algorithm is not nullptr");
276 delete algorithm;
277 }
278 }
279 } // namespace DeviceStatus
280 } // namespace Msdp
281 } // namespace OHOS
282