1 /*
2 * Copyright (c) 2021-2025 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 "uds_server.h"
17
18 #include "dfx_hisysevent.h"
19 #include "imultimodal_input_connect.h"
20 #include "multimodal_input_connect_manager.h"
21 #include "util_ex.h"
22
23 #undef MMI_LOG_DOMAIN
24 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
25 #undef MMI_LOG_TAG
26 #define MMI_LOG_TAG "UDSServer"
27
28 namespace OHOS {
29 namespace MMI {
~UDSServer()30 UDSServer::~UDSServer()
31 {
32 CALL_DEBUG_ENTER;
33 UdsStop();
34 }
35
UdsStop()36 void UDSServer::UdsStop()
37 {
38 if (epollFd_ != -1) {
39 int32_t tmpFd = epollFd_;
40 epollFd_ = -1;
41 close(tmpFd);
42 }
43 auto tmpMap = GetSessionMapCopy();
44 for (const auto &item : tmpMap) {
45 CHKPC(item.second);
46 item.second->Close();
47 }
48 ClearSessionMap();
49 }
50
GetClientFd(int32_t pid) const51 int32_t UDSServer::GetClientFd(int32_t pid) const
52 {
53 std::lock_guard<std::mutex> lock(idxPidMapMutex_);
54 auto it = idxPidMap_.find(pid);
55 if (it == idxPidMap_.end()) {
56 if (pid_ != pid) {
57 pid_ = pid;
58 MMI_HILOGE("Not found pid:%{public}d", pid);
59 }
60 return INVALID_FD;
61 }
62 return it->second;
63 }
64
GetClientPid(int32_t fd) const65 int32_t UDSServer::GetClientPid(int32_t fd) const
66 {
67 auto sp = GetSession(fd);
68 if (sp == nullptr) {
69 MMI_HILOGE("Not found fd:%{public}d", fd);
70 return INVALID_PID;
71 }
72 return sp->GetPid();
73 }
74
SendMsg(int32_t fd,NetPacket & pkt)75 bool UDSServer::SendMsg(int32_t fd, NetPacket& pkt)
76 {
77 if (fd < 0) {
78 MMI_HILOGE("The fd is less than 0");
79 return false;
80 }
81 auto ses = GetSession(fd);
82 if (ses == nullptr) {
83 MMI_HILOGE("The fd:%{public}d not found, The message was discarded. errCode:%{public}d",
84 fd, SESSION_NOT_FOUND);
85 return false;
86 }
87 return ses->SendMsg(pkt);
88 }
89
Multicast(const std::vector<int32_t> & fdList,NetPacket & pkt)90 void UDSServer::Multicast(const std::vector<int32_t>& fdList, NetPacket& pkt)
91 {
92 for (const auto &item : fdList) {
93 SendMsg(item, pkt);
94 }
95 }
96
AddSocketPairInfo(const std::string & programName,const int32_t moduleType,const int32_t uid,const int32_t pid,int32_t & serverFd,int32_t & toReturnClientFd,int32_t & tokenType)97 int32_t UDSServer::AddSocketPairInfo(const std::string& programName,
98 const int32_t moduleType, const int32_t uid, const int32_t pid,
99 int32_t& serverFd, int32_t& toReturnClientFd, int32_t& tokenType)
100 {
101 CALL_DEBUG_ENTER;
102 int32_t sockFds[2] = { -1 };
103
104 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) != 0) {
105 MMI_HILOGE("Call socketpair failed, errno:%{public}d", errno);
106 return RET_ERR;
107 }
108 fdsan_exchange_owner_tag(sockFds[0], 0, TAG);
109 fdsan_exchange_owner_tag(sockFds[1], 0, TAG);
110 serverFd = sockFds[0];
111 toReturnClientFd = sockFds[1];
112 if (serverFd < 0 || toReturnClientFd < 0) {
113 MMI_HILOGE("Call fcntl failed, errno:%{public}d", errno);
114 return RET_ERR;
115 }
116
117 SessionPtr sess = nullptr;
118 bool readOnly = false;
119 if (SetFdProperty(tokenType, serverFd, toReturnClientFd, programName, readOnly) != RET_OK) {
120 MMI_HILOGE("SetFdProperty failed");
121 goto CLOSE_SOCK;
122 }
123
124 if (AddEpoll(EPOLL_EVENT_SOCKET, serverFd, readOnly) != RET_OK) {
125 MMI_HILOGE("Add epoll failed, errCode:%{public}d", EPOLL_MODIFY_FAIL);
126 goto CLOSE_SOCK;
127 }
128 sess = std::make_shared<UDSSession>(programName, moduleType, serverFd, uid, pid);
129 if (sess == nullptr) {
130 MMI_HILOGE("Make shared pointer fail. programName:%{public}s, pid:%{public}d, errCode:%{public}d",
131 programName.c_str(), pid, MAKE_SHARED_FAIL);
132 goto CLOSE_SOCK;
133 }
134 sess->SetTokenType(tokenType);
135 if (!AddSession(sess)) {
136 MMI_HILOGE("AddSession fail errCode:%{public}d", ADD_SESSION_FAIL);
137 goto CLOSE_SOCK;
138 }
139 OnConnected(sess);
140 return RET_OK;
141
142 CLOSE_SOCK:
143 fdsan_close_with_tag(sockFds[0], TAG);
144 serverFd = MultimodalInputConnectManager::INVALID_SOCKET_FD;
145 fdsan_close_with_tag(sockFds[1], TAG);
146 toReturnClientFd = MultimodalInputConnectManager::INVALID_SOCKET_FD;
147 return RET_ERR;
148 }
149
SetFdProperty(int32_t & tokenType,int32_t & serverFd,int32_t & toReturnClientFd,const std::string & programName,bool & readOnly)150 int32_t UDSServer::SetFdProperty(int32_t &tokenType, int32_t &serverFd, int32_t &toReturnClientFd,
151 const std::string &programName, bool &readOnly)
152 {
153 static size_t bufferSize = 64 * 1024;
154 static size_t serverBufferSize = 64 * 1024;
155 static size_t nativeBufferSize = 128 * 1024;
156 #ifdef OHOS_BUILD_ENABLE_ANCO
157 bufferSize = 512 * 1024;
158 nativeBufferSize = 1024 * 1024;
159 #endif // OHOS_BUILD_ENABLE_ANCO
160
161 if (setsockopt(serverFd, SOL_SOCKET, SO_SNDBUF, &serverBufferSize, sizeof(bufferSize)) != 0) {
162 MMI_HILOGE("Setsockopt serverFd failed, errno:%{public}d", errno);
163 return RET_ERR;
164 }
165 if (setsockopt(serverFd, SOL_SOCKET, SO_RCVBUF, &serverBufferSize, sizeof(bufferSize)) != 0) {
166 MMI_HILOGE("Setsockopt serverFd failed, errno:%{public}d", errno);
167 return RET_ERR;
168 }
169 if (tokenType == TokenType::TOKEN_NATIVE) {
170 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_SNDBUF, &nativeBufferSize, sizeof(nativeBufferSize)) != 0) {
171 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
172 return RET_ERR;
173 }
174 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_RCVBUF, &nativeBufferSize, sizeof(nativeBufferSize)) != 0) {
175 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
176 return RET_ERR;
177 }
178 } else {
179 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize)) != 0) {
180 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
181 return RET_ERR;
182 }
183 if (setsockopt(toReturnClientFd, SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize)) != 0) {
184 MMI_HILOGE("Setsockopt toReturnClientFd failed, errno:%{public}d", errno);
185 return RET_ERR;
186 }
187 }
188 const std::vector<std::string> programWhitelist = {
189 "com.ohos.systemui", "security_component_service"};
190 if (std::find(programWhitelist.begin(), programWhitelist.end(), programName) == programWhitelist.end()) {
191 MMI_HILOGD("toReturnClientFd shutdown SHUT_WR , programName:%{public}s", programName.c_str());
192 }
193 return RET_OK;
194 }
195
Dump(int32_t fd,const std::vector<std::string> & args)196 void UDSServer::Dump(int32_t fd, const std::vector<std::string> &args)
197 {
198 CALL_DEBUG_ENTER;
199 mprintf(fd, "Uds_server information:\t");
200 mprintf(fd, "uds_server: count=%zu", GetSessionSize());
201 auto tmpMap = GetSessionMapCopy();
202 for (const auto &item : tmpMap) {
203 std::shared_ptr<UDSSession> udsSession = item.second;
204 CHKPV(udsSession);
205 mprintf(fd,
206 "Uid:%d | Pid:%d | Fd:%d | TokenType:%d | Descript:%s\t",
207 udsSession->GetUid(), udsSession->GetPid(), udsSession->GetFd(),
208 udsSession->GetTokenType(), udsSession->GetDescript().c_str());
209 }
210 }
211
OnConnected(SessionPtr sess)212 void UDSServer::OnConnected(SessionPtr sess)
213 {
214 CHKPV(sess);
215 MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str());
216 }
217
OnDisconnected(SessionPtr sess)218 void UDSServer::OnDisconnected(SessionPtr sess)
219 {
220 CHKPV(sess);
221 MMI_HILOGI("Session desc:%{public}s", sess->GetDescript().c_str());
222 }
223
AddEpoll(EpollEventType type,int32_t fd,bool readOnly)224 int32_t UDSServer::AddEpoll(EpollEventType type, int32_t fd, bool readOnly)
225 {
226 MMI_HILOGE("This information should not exist. Subclasses should implement this function");
227 return RET_ERR;
228 }
229
SetRecvFun(MsgServerFunCallback fun)230 void UDSServer::SetRecvFun(MsgServerFunCallback fun)
231 {
232 recvFun_ = fun;
233 }
234
ReleaseSession(int32_t fd,epoll_event & ev)235 void UDSServer::ReleaseSession(int32_t fd, epoll_event& ev)
236 {
237 CALL_DEBUG_ENTER;
238 auto secPtr = GetSession(fd);
239 if (secPtr != nullptr) {
240 OnDisconnected(secPtr);
241 DelSession(fd);
242 } else {
243 MMI_HILOGE("Get session secPtr is nullptr, fd:%{public}d", fd);
244 DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::FAULT);
245 }
246 if (ev.data.ptr) {
247 RemoveEpollEvent(fd);
248 ev.data.ptr = nullptr;
249 }
250 if (auto it = circleBufMap_.find(fd); it != circleBufMap_.end()) {
251 circleBufMap_.erase(it);
252 } else {
253 MMI_HILOGE("Can't find fd");
254 }
255 if (fdsan_close_with_tag(fd, TAG) == RET_OK) {
256 DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::BEHAVIOR);
257 } else {
258 DfxHisysevent::OnClientDisconnect(secPtr, fd, OHOS::HiviewDFX::HiSysEvent::EventType::FAULT);
259 }
260 }
261
OnPacket(int32_t fd,NetPacket & pkt)262 void UDSServer::OnPacket(int32_t fd, NetPacket& pkt)
263 {
264 auto sess = GetSession(fd);
265 CHKPV(sess);
266 recvFun_(sess, pkt);
267 }
268
OnEpollRecv(int32_t fd,epoll_event & ev)269 void UDSServer::OnEpollRecv(int32_t fd, epoll_event& ev)
270 {
271 if (fd < 0) {
272 MMI_HILOGE("Invalid input param fd:%{public}d", fd);
273 return;
274 }
275 auto& buf = circleBufMap_[fd];
276 char szBuf[MAX_PACKET_BUF_SIZE] = {};
277 for (int32_t i = 0; i < MAX_RECV_LIMIT; i++) {
278 auto size = recv(fd, szBuf, MAX_PACKET_BUF_SIZE, MSG_DONTWAIT | MSG_NOSIGNAL);
279 if (size > 0) {
280 if (!buf.Write(szBuf, size)) {
281 MMI_HILOGW("Write data failed. size:%{public}zu", size);
282 }
283 OnReadPackets(buf, [this, fd] (NetPacket& pkt) { return this->OnPacket(fd, pkt); });
284 } else if (size < 0) {
285 if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) {
286 MMI_HILOGD("Continue for errno EAGAIN|EINTR|EWOULDBLOCK size:%{public}zu, errno:%{public}d",
287 size, errno);
288 continue;
289 }
290 MMI_HILOGE("Recv return %{public}zu errno:%{public}d", size, errno);
291 break;
292 } else {
293 MMI_HILOGE("The client side disconnect with the server. size:0 errno:%{public}d", errno);
294 ReleaseSession(fd, ev);
295 break;
296 }
297 if (size < MAX_PACKET_BUF_SIZE) {
298 break;
299 }
300 }
301 }
302
OnEpollEvent(epoll_event & ev)303 void UDSServer::OnEpollEvent(epoll_event& ev)
304 {
305 CHKPV(ev.data.ptr);
306 auto fd = ev.data.fd;
307 if (fd < 0) {
308 MMI_HILOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
309 return;
310 }
311 if ((ev.events & EPOLLERR) || (ev.events & EPOLLHUP)) {
312 MMI_HILOGI("EPOLLERR or EPOLLHUP fd:%{public}d, ev.events:0x%{public}x", fd, ev.events);
313 ReleaseSession(fd, ev);
314 } else if (ev.events & EPOLLIN) {
315 OnEpollRecv(fd, ev);
316 }
317 }
318
AddEpollEvent(int32_t fd,std::shared_ptr<mmi_epoll_event> epollEvent)319 void UDSServer::AddEpollEvent(int32_t fd, std::shared_ptr<mmi_epoll_event> epollEvent)
320 {
321 MMI_HILOGI("Add %{public}d in epollEvent map", fd);
322 epollEventMap_[fd] = epollEvent;
323 }
324
RemoveEpollEvent(int32_t fd)325 void UDSServer::RemoveEpollEvent(int32_t fd)
326 {
327 MMI_HILOGI("Remove %{public}d in epollEvent map", fd);
328 epollEventMap_.erase(fd);
329 }
330
DumpSession(const std::string & title)331 void UDSServer::DumpSession(const std::string &title)
332 {
333 MMI_HILOGD("in %s: %s", __func__, title.c_str());
334 int32_t i = 0;
335 auto tmpMap = GetSessionMapCopy();
336 for (auto &[key, value] : tmpMap) {
337 CHKPV(value);
338 MMI_HILOGD("%d, %s", i, value->GetDescript().c_str());
339 i++;
340 }
341 }
342
GetSession(int32_t fd) const343 SessionPtr UDSServer::GetSession(int32_t fd) const
344 {
345 std::lock_guard<std::mutex> lock(sessionsMapMutex_);
346 auto it = sessionsMap_.find(fd);
347 if (it == sessionsMap_.end()) {
348 MMI_HILOGE("Session not found. fd:%{public}d", fd);
349 return nullptr;
350 }
351 CHKPP(it->second);
352 return it->second->GetSharedPtr();
353 }
354
EarseSessionByFd(int32_t fd)355 void UDSServer::EarseSessionByFd(int32_t fd)
356 {
357 std::lock_guard<std::mutex> lock(sessionsMapMutex_);
358 auto it = sessionsMap_.find(fd);
359 if (it == sessionsMap_.end()) {
360 MMI_HILOGI("Session not found. fd:%{public}d", fd);
361 return;
362 }
363 sessionsMap_.erase(it);
364 }
365
GetSessionSize()366 size_t UDSServer::GetSessionSize()
367 {
368 std::lock_guard<std::mutex> lock(sessionsMapMutex_);
369 return sessionsMap_.size();
370 }
371
InsertSession(int32_t fd,SessionPtr sp)372 bool UDSServer::InsertSession(int32_t fd, SessionPtr sp)
373 {
374 if (fd < 0 || sp == nullptr) {
375 MMI_HILOGE("invalid param");
376 return false;
377 }
378 std::lock_guard<std::mutex> lock(sessionsMapMutex_);
379 sessionsMap_[fd] = sp;
380 if (sessionsMap_.size() > MAX_SESSON_ALARM) {
381 MMI_HILOGW("Too many clients. Warning Value:%{public}d, Current Value:%{public}zd",
382 MAX_SESSON_ALARM, sessionsMap_.size());
383 }
384 return true;
385 }
386
GetSessionMapCopy()387 std::map<int32_t, SessionPtr> UDSServer::GetSessionMapCopy()
388 {
389 std::lock_guard<std::mutex> lock(sessionsMapMutex_);
390 return sessionsMap_;
391 }
392
ClearSessionMap()393 void UDSServer::ClearSessionMap()
394 {
395 std::lock_guard<std::mutex> lock(sessionsMapMutex_);
396 sessionsMap_.clear();
397 }
398
GetSessionByPid(int32_t pid) const399 SessionPtr UDSServer::GetSessionByPid(int32_t pid) const
400 {
401 int32_t fd = GetClientFd(pid);
402 if (fd <= 0) {
403 if (pid_ != pid) {
404 pid_ = pid;
405 MMI_HILOGE("Session not found. pid:%{public}d", pid);
406 }
407 return nullptr;
408 }
409 return GetSession(fd);
410 }
411
AddSession(SessionPtr ses)412 bool UDSServer::AddSession(SessionPtr ses)
413 {
414 CHKPF(ses);
415 MMI_HILOGI("The pid:%{public}d, fd:%{public}d", ses->GetPid(), ses->GetFd());
416 auto fd = ses->GetFd();
417 if (fd < 0) {
418 MMI_HILOGE("The fd is less than 0");
419 return false;
420 }
421 auto pid = ses->GetPid();
422 if (pid <= 0) {
423 MMI_HILOGE("Get process failed");
424 return false;
425 }
426 {
427 std::lock_guard<std::mutex> lock(idxPidMapMutex_);
428 idxPidMap_[pid] = fd;
429 }
430 if (InsertSession(fd, ses) != true) {
431 return false;
432 }
433 DumpSession("AddSession");
434 MMI_HILOGI("AddSession end");
435 return true;
436 }
437
DelSession(int32_t fd)438 void UDSServer::DelSession(int32_t fd)
439 {
440 CALL_DEBUG_ENTER;
441 MMI_HILOGI("The fd:%{public}d", fd);
442 if (fd < 0) {
443 MMI_HILOGE("The fd less than 0, errCode:%{public}d", PARAM_INPUT_INVALID);
444 return;
445 }
446 auto pid = GetClientPid(fd);
447 MMI_HILOGI("The pid:%{public}d", pid);
448 if (pid > 0) {
449 std::lock_guard<std::mutex> lock(idxPidMapMutex_);
450 idxPidMap_.erase(pid);
451 }
452 SessionPtr sp = GetSession(fd);
453 if (sp != nullptr) {
454 NotifySessionDeleted(sp);
455 EarseSessionByFd(fd);
456 }
457 DumpSession("DelSession");
458 }
459
AddSessionDeletedCallback(std::function<void (SessionPtr)> callback)460 void UDSServer::AddSessionDeletedCallback(std::function<void(SessionPtr)> callback)
461 {
462 CALL_DEBUG_ENTER;
463 callbacks_.push_back(callback);
464 }
465
NotifySessionDeleted(SessionPtr ses)466 void UDSServer::NotifySessionDeleted(SessionPtr ses)
467 {
468 CALL_DEBUG_ENTER;
469 for (const auto &callback : callbacks_) {
470 callback(ses);
471 }
472 }
473 } // namespace MMI
474 } // namespace OHOS
475