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 32namespace OHOS { 33namespace Msdp { 34namespace DeviceStatus { 35namespace { 36constexpr int32_t TIMER_INTERVAL { 3 }; 37constexpr int32_t ERR_INVALID_FD { -1 }; 38DeviceStatusMsdpMock* g_msdpMock { nullptr }; 39} // namespace 40 41DeviceStatusMsdpMock::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 53DeviceStatusMsdpMock::~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 64bool DeviceStatusMsdpMock::Init() 65{ 66 CALL_DEBUG_ENTER; 67 InitTimer(); 68 StartThread(); 69 return true; 70} 71 72ErrCode DeviceStatusMsdpMock::RegisterCallback(std::shared_ptr<MsdpAlgoCallback> callback) 73{ 74 std::lock_guard lock(mutex_); 75 callback_ = callback; 76 return RET_OK; 77} 78 79ErrCode DeviceStatusMsdpMock::UnregisterCallback() 80{ 81 std::lock_guard lock(mutex_); 82 callback_ = nullptr; 83 return RET_OK; 84} 85 86ErrCode DeviceStatusMsdpMock::Enable(Type type) 87{ 88 CALL_DEBUG_ENTER; 89 Init(); 90 return RET_OK; 91} 92 93ErrCode 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 105ErrCode DeviceStatusMsdpMock::DisableCount(Type type) 106{ 107 CALL_DEBUG_ENTER; 108 CHKPR(dataParse_, RET_ERR); 109 dataParse_->DisableCount(type); 110 return RET_OK; 111} 112 113ErrCode 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 123void 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 152int32_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 175void 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 187void 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 197int32_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 210int32_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 229void DeviceStatusMsdpMock::StartThread() 230{ 231 CALL_DEBUG_ENTER; 232 if (!alive_) { 233 alive_ = true; 234 thread_ = std::thread([this] { this->LoopingThreadEntry(); }); 235 } 236} 237 238void 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 263extern "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 271extern "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