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