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