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