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