1/* 2 * Copyright (c) 2021-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 "client.h" 17 18#include <cinttypes> 19#include <condition_variable> 20 21#include "devicestatus_client.h" 22#include "fd_listener.h" 23#include "fi_log.h" 24#include "proto.h" 25#include "time_cost_chk.h" 26#include "include/util.h" 27 28#undef LOG_TAG 29#define LOG_TAG "Client" 30 31namespace OHOS { 32namespace Msdp { 33namespace DeviceStatus { 34namespace { 35const std::string THREAD_NAME { "os_ClientEventHandler" }; 36} // namespace 37 38using namespace AppExecFwk; 39Client::~Client() 40{ 41 CALL_DEBUG_ENTER; 42 Stop(); 43} 44 45void Client::SetEventHandler(EventHandlerPtr eventHandler) 46{ 47 CHKPV(eventHandler); 48 eventHandler_ = eventHandler; 49} 50 51void Client::MarkIsEventHandlerChanged(EventHandlerPtr eventHandler) 52{ 53 CHKPV(eventHandler); 54 CHKPV(eventHandler_); 55 auto currentRunner = eventHandler_->GetEventRunner(); 56 CHKPV(currentRunner); 57 auto newEventRunner = eventHandler->GetEventRunner(); 58 CHKPV(newEventRunner); 59 isEventHandlerChanged_ = false; 60 if (currentRunner->GetRunnerThreadName() != newEventRunner->GetRunnerThreadName()) { 61 isEventHandlerChanged_ = true; 62 FI_HILOGD("Event handler changed"); 63 } 64 FI_HILOGD("Current handler name:%{public}s, New handler name:%{public}s", 65 currentRunner->GetRunnerThreadName().c_str(), newEventRunner->GetRunnerThreadName().c_str()); 66} 67 68bool Client::SendMessage(const NetPacket &pkt) const 69{ 70 return SendMsg(pkt); 71} 72 73bool Client::GetCurrentConnectedStatus() const 74{ 75 return GetConnectedStatus(); 76} 77 78IClientPtr Client::GetSharedPtr() 79{ 80 return shared_from_this(); 81} 82 83bool Client::Start() 84{ 85 CALL_DEBUG_ENTER; 86 auto callback = [this](const StreamClient &client, NetPacket &pkt) { 87 this->OnMsgHandler(client, pkt); 88 }; 89 if (!StartClient(callback)) { 90 FI_HILOGE("Client startup failed"); 91 Stop(); 92 return false; 93 } 94 if (!StartEventRunner()) { 95 FI_HILOGE("Start runner failed"); 96 Stop(); 97 return false; 98 } 99 FI_HILOGD("Client started successfully"); 100 return true; 101} 102 103bool Client::StartEventRunner() 104{ 105 CALL_DEBUG_ENTER; 106 CHK_PID_AND_TID(); 107 auto runner = AppExecFwk::EventRunner::Create(THREAD_NAME); 108 CHKPF(runner); 109 eventHandler_ = std::make_shared<AppExecFwk::EventHandler>(runner); 110 111 FI_HILOGI("Create event handler, thread name:%{public}s", runner->GetRunnerThreadName().c_str()); 112 113 if (hasConnected_ && fd_ >= 0) { 114 if (isListening_) { 115 FI_HILOGI("File fd is in listening"); 116 return true; 117 } 118 if (!AddFdListener(fd_)) { 119 FI_HILOGE("Add fd listener failed"); 120 return false; 121 } 122 } else { 123 if (!eventHandler_->PostTask([this] { this->OnReconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) { 124 FI_HILOGE("Send reconnect event failed"); 125 return false; 126 } 127 } 128 return true; 129} 130 131bool Client::AddFdListener(int32_t fd) 132{ 133 CALL_DEBUG_ENTER; 134 if (fd < 0) { 135 FI_HILOGE("Invalid fd:%{public}d", fd); 136 return false; 137 } 138 CHKPF(eventHandler_); 139 auto fdListener = std::make_shared<FdListener>(GetSharedPtr()); 140 auto errCode = eventHandler_->AddFileDescriptorListener(fd, FILE_DESCRIPTOR_INPUT_EVENT, fdListener, 141 "DeviceStatusTask"); 142 if (errCode != ERR_OK) { 143 FI_HILOGE("Add fd listener failed, fd:%{public}d, code:%{public}u, str:%{public}s", fd, errCode, 144 GetErrorStr(errCode).c_str()); 145 return false; 146 } 147 isRunning_ = true; 148 FI_HILOGI("serverFd:%{public}d was listening, mask:%{public}u," PRIu64, fd, FILE_DESCRIPTOR_INPUT_EVENT); 149 return true; 150} 151 152bool Client::DelFdListener(int32_t fd) 153{ 154 CALL_DEBUG_ENTER; 155 CHKPF(eventHandler_); 156 if (fd >= 0) { 157 eventHandler_->RemoveFileDescriptorListener(fd); 158 FI_HILOGI("Remove file descriptor listener success"); 159 } else { 160 FI_HILOGE("Invalid fd:%{public}d", fd); 161 } 162 auto runner = eventHandler_->GetEventRunner(); 163 CHKPF(runner); 164 if (runner->GetRunnerThreadName() == THREAD_NAME) { 165 eventHandler_->RemoveAllEvents(); 166 FI_HILOGI("Remove all events success"); 167 } 168 isRunning_ = false; 169 return true; 170} 171 172void Client::OnPacket(NetPacket &pkt) 173{ 174 recvFun_(*this, pkt); 175} 176 177void Client::OnRecvMsg(const char *buf, size_t size) 178{ 179 CHKPV(buf); 180 if (size == 0 || size > MAX_PACKET_BUF_SIZE) { 181 FI_HILOGE("Invalid input param size, size:%{public}zu", size); 182 return; 183 } 184 if (!circBuf_.Write(buf, size)) { 185 FI_HILOGW("Write data failed, size:%{public}zu", size); 186 } 187 OnReadPackets(circBuf_, [this](NetPacket &pkt) { this->OnPacket(pkt); }); 188} 189 190int32_t Client::Reconnect() 191{ 192 return StartConnect(); 193} 194 195void Client::OnReconnect() 196{ 197 if (Reconnect() == RET_OK) { 198 FI_HILOGI("Reconnect ok"); 199 return; 200 } 201 CHKPV(eventHandler_); 202 if (!eventHandler_->PostTask([this] { this->OnReconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) { 203 FI_HILOGE("Post reconnect event failed"); 204 } 205} 206 207void Client::OnDisconnect() 208{ 209 OnDisconnected(); 210} 211 212void Client::RegisterConnectedFunction(ConnectCallback function) 213{ 214 funConnected_ = function; 215} 216 217void Client::RegisterDisconnectedFunction(ConnectCallback fun) 218{ 219 funDisconnected_ = fun; 220} 221 222void Client::OnDisconnected() 223{ 224 CALL_DEBUG_ENTER; 225 FI_HILOGI("Disconnected from server, fd:%{public}d", fd_); 226 hasConnected_ = false; 227 isListening_ = false; 228 if (funDisconnected_ != nullptr) { 229 FI_HILOGI("Execute funDisconnected"); 230 funDisconnected_(); 231 } 232 if (!DelFdListener(fd_)) { 233 FI_HILOGW("Delete fd listener failed"); 234 } 235 StreamClient::Stop(); 236 if (hasClient_ && eventHandler_ != nullptr) { 237 if (!eventHandler_->PostTask([this] { this->OnReconnect(); }, CLIENT_RECONNECT_COOLING_TIME)) { 238 FI_HILOGE("Send reconnect event task failed"); 239 } 240 } 241} 242 243void Client::OnConnected() 244{ 245 CALL_DEBUG_ENTER; 246 FI_HILOGI("Connection to server succeeded, fd:%{public}d", GetFd()); 247 hasConnected_ = true; 248 if (funConnected_ != nullptr) { 249 FI_HILOGI("Execute funConnected"); 250 funConnected_(); 251 } 252 if (hasClient_ && !isRunning_ && fd_ >= 0 && eventHandler_ != nullptr) { 253 if (!AddFdListener(fd_)) { 254 FI_HILOGE("Add fd listener failed"); 255 return; 256 } 257 isListening_ = true; 258 } 259} 260 261int32_t Client::Socket() 262{ 263 CALL_DEBUG_ENTER; 264 return -1; 265} 266 267void Client::Stop() 268{ 269 CALL_DEBUG_ENTER; 270 StreamClient::Stop(); 271 isRunning_ = false; 272 if (eventHandler_ != nullptr) { 273 auto runner = eventHandler_->GetEventRunner(); 274 CHKPV(runner); 275 if (runner->GetRunnerThreadName() == THREAD_NAME) { 276 runner->Stop(); 277 eventHandler_->RemoveAllEvents(); 278 eventHandler_->RemoveAllFileDescriptorListeners(); 279 FI_HILOGI("Remove all file descriptor listeners success"); 280 } 281 } 282} 283 284void Client::OnMsgHandler(const StreamClient &client, NetPacket &pkt) 285{ 286 CALL_DEBUG_ENTER; 287 auto id = pkt.GetMsgId(); 288 TimeCostChk chk("Client::OnMsgHandler", "overtime 300(us)", MAX_OVER_TIME, id); 289 auto callback = GetMsgCallback(id); 290 if (callback == nullptr) { 291 FI_HILOGE("Unknown msg id:%{public}d", id); 292 return; 293 } 294 int32_t ret = (*callback)(client, pkt); 295 if (ret < 0) { 296 FI_HILOGE("Msg handling failed, id:%{public}d, ret:%{public}d", id, ret); 297 return; 298 } 299} 300 301const std::string& Client::GetErrorStr(ErrCode code) const 302{ 303 const static std::string defErrString = "Unknown event handler error!"; 304 const static std::map<ErrCode, std::string> mapStrings = { 305 { ERR_OK, "ERR_OK" }, 306 { EVENT_HANDLER_ERR_INVALID_PARAM, "Invalid parameters" }, 307 { EVENT_HANDLER_ERR_NO_EVENT_RUNNER, "Have not set event runner yet" }, 308 { EVENT_HANDLER_ERR_FD_NOT_SUPPORT, "Not support to listen file descriptors" }, 309 { EVENT_HANDLER_ERR_FD_ALREADY, "File descriptor is already in listening" }, 310 { EVENT_HANDLER_ERR_FD_FAILED, "Failed to listen file descriptor" }, 311 { EVENT_HANDLER_ERR_RUNNER_NO_PERMIT, "No permit to start or stop deposited event runner" }, 312 { EVENT_HANDLER_ERR_RUNNER_ALREADY, "Event runner is already running" } 313 }; 314 auto it = mapStrings.find(code); 315 if (it != mapStrings.end()) { 316 return it->second; 317 } 318 return defErrString; 319} 320} // namespace DeviceStatus 321} // namespace Msdp 322} // namespace OHOS 323