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