1 /*
2 * Copyright (c) 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 "socket_session_manager.h"
17
18 #include <algorithm>
19
20 #include <sys/socket.h>
21 #include <unistd.h>
22
23 #include "iservice_registry.h"
24 #include "system_ability_definition.h"
25
26 #include "devicestatus_define.h"
27
28 #undef LOG_TAG
29 #define LOG_TAG "SocketSessionManager"
30
31 namespace OHOS {
32 namespace Msdp {
33 namespace DeviceStatus {
34 namespace {
35 constexpr int32_t MAX_EPOLL_EVENTS { 64 };
36 } // namespace
37
~SocketSessionManager()38 SocketSessionManager::~SocketSessionManager()
39 {
40 Disable();
41 }
42
Enable()43 int32_t SocketSessionManager::Enable()
44 {
45 CALL_INFO_TRACE;
46 std::lock_guard<std::recursive_mutex> guard(mutex_);
47 if (!epollMgr_.Open()) {
48 FI_HILOGE("EpollMgr::Open fail");
49 return RET_ERR;
50 }
51 return RET_OK;
52 }
53
Disable()54 void SocketSessionManager::Disable()
55 {
56 CALL_INFO_TRACE;
57 std::lock_guard<std::recursive_mutex> guard(mutex_);
58 epollMgr_.Close();
59 std::for_each(sessions_.cbegin(), sessions_.cend(), [this](const auto &item) {
60 CHKPV(item.second);
61 NotifySessionDeleted(item.second);
62 });
63 sessions_.clear();
64 }
65
RegisterApplicationState()66 void SocketSessionManager::RegisterApplicationState()
67 {
68 CALL_DEBUG_ENTER;
69 auto appMgr = GetAppMgr();
70 CHKPV(appMgr);
71 appStateObserver_ = sptr<AppStateObserver>::MakeSptr(*this);
72 auto err = appMgr->RegisterApplicationStateObserver(appStateObserver_);
73 if (err != RET_OK) {
74 appStateObserver_ = nullptr;
75 FI_HILOGE("IAppMgr::RegisterApplicationStateObserver fail, error:%{public}d", err);
76 }
77 }
78
OnProcessDied(const AppExecFwk::ProcessData &processData)79 void SocketSessionManager::AppStateObserver::OnProcessDied(const AppExecFwk::ProcessData &processData)
80 {
81 FI_HILOGI("\'%{public}s\' died, pid:%{public}d", processData.bundleName.c_str(), processData.pid);
82 socketSessionManager_.ReleaseSessionByPid(processData.pid);
83 }
84
AllocSocketFd(const std::string& programName, int32_t moduleType, int32_t tokenType, int32_t uid, int32_t pid, int32_t& clientFd)85 int32_t SocketSessionManager::AllocSocketFd(const std::string& programName, int32_t moduleType, int32_t tokenType,
86 int32_t uid, int32_t pid, int32_t& clientFd)
87 {
88 CALL_DEBUG_ENTER;
89 int32_t sockFds[2] { -1, -1 };
90
91 if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sockFds) != 0) {
92 FI_HILOGE("Call socketpair failed, errno:%{public}s", ::strerror(errno));
93 return RET_ERR;
94 }
95 static constexpr size_t BUFFER_SIZE { 32 * 1024 };
96 static constexpr size_t NATIVE_BUFFER_SIZE { 64 * 1024 };
97 std::shared_ptr<SocketSession> session { nullptr };
98
99 if (!SetBufferSize(sockFds[0], BUFFER_SIZE)) {
100 goto CLOSE_SOCK;
101 }
102 if (!SetBufferSize(sockFds[1], tokenType == TokenType::TOKEN_NATIVE ? NATIVE_BUFFER_SIZE : BUFFER_SIZE)) {
103 goto CLOSE_SOCK;
104 }
105
106 session = std::make_shared<SocketSession>(programName, moduleType, tokenType, sockFds[0], uid, pid);
107 if (!AddSession(session)) {
108 FI_HILOGE("AddSession failed, errCode:%{public}d", ADD_SESSION_FAIL);
109 goto CLOSE_SOCK;
110 }
111
112 clientFd = sockFds[1];
113 return RET_OK;
114
115 CLOSE_SOCK:
116 if (::close(sockFds[0]) != 0) {
117 FI_HILOGE("close(%{public}d) failed:%{public}s", sockFds[0], ::strerror(errno));
118 }
119 if (::close(sockFds[1]) != 0) {
120 FI_HILOGE("close(%{public}d) failed:%{public}s", sockFds[1], ::strerror(errno));
121 }
122 return RET_ERR;
123 }
124
SetBufferSize(int32_t sockFd, int32_t bufSize)125 bool SocketSessionManager::SetBufferSize(int32_t sockFd, int32_t bufSize)
126 {
127 if (::setsockopt(sockFd, SOL_SOCKET, SO_SNDBUF, &bufSize, sizeof(bufSize)) != 0) {
128 FI_HILOGE("setsockopt(%{public}d) failed:%{public}s", sockFd, ::strerror(errno));
129 return false;
130 }
131 if (::setsockopt(sockFd, SOL_SOCKET, SO_RCVBUF, &bufSize, sizeof(bufSize)) != 0) {
132 FI_HILOGE("setsockopt(%{public}d) failed:%{public}s", sockFd, ::strerror(errno));
133 return false;
134 }
135 return true;
136 }
137
FindSessionByPid(int32_t pid) const138 SocketSessionPtr SocketSessionManager::FindSessionByPid(int32_t pid) const
139 {
140 std::lock_guard<std::recursive_mutex> guard(mutex_);
141 auto iter = std::find_if(sessions_.cbegin(), sessions_.cend(),
142 [pid](const auto &item) {
143 return ((item.second != nullptr) && (item.second->GetPid() == pid));
144 });
145 return (iter != sessions_.cend() ? iter->second : nullptr);
146 }
147
Dispatch(const struct epoll_event &ev)148 void SocketSessionManager::Dispatch(const struct epoll_event &ev)
149 {
150 if ((ev.events & EPOLLIN) == EPOLLIN) {
151 DispatchOne();
152 } else if ((ev.events & (EPOLLHUP | EPOLLERR)) != 0) {
153 FI_HILOGE("Epoll hangup:%{public}s", ::strerror(errno));
154 }
155 }
156
DispatchOne()157 void SocketSessionManager::DispatchOne()
158 {
159 struct epoll_event evs[MAX_EPOLL_EVENTS];
160 std::lock_guard<std::recursive_mutex> guard(mutex_);
161 int32_t cnt = epollMgr_.WaitTimeout(evs, MAX_EPOLL_EVENTS, 0);
162
163 for (int32_t index = 0; index < cnt; ++index) {
164 IEpollEventSource *source = reinterpret_cast<IEpollEventSource *>(evs[index].data.ptr);
165 CHKPC(source);
166 if ((evs[index].events & EPOLLIN) == EPOLLIN) {
167 OnEpollIn(*source);
168 } else if ((evs[index].events & (EPOLLHUP | EPOLLERR)) != 0) {
169 FI_HILOGW("Epoll hangup:%{public}s", ::strerror(errno));
170 ReleaseSession(source->GetFd());
171 }
172 }
173 }
174
OnEpollIn(IEpollEventSource &source)175 void SocketSessionManager::OnEpollIn(IEpollEventSource &source)
176 {
177 CALL_DEBUG_ENTER;
178 char buf[MAX_PACKET_BUF_SIZE] {};
179 ssize_t numRead {};
180
181 do {
182 numRead = ::recv(source.GetFd(), buf, sizeof(buf), MSG_DONTWAIT);
183 if (numRead > 0) {
184 FI_HILOGI("%{public}zd bytes received", numRead);
185 } else if (numRead < 0) {
186 if (errno == EINTR) {
187 FI_HILOGD("recv was interrupted, read again");
188 continue;
189 }
190 if ((errno == EAGAIN) || (errno == EWOULDBLOCK)) {
191 FI_HILOGW("No available data");
192 } else {
193 FI_HILOGE("recv failed:%{public}s", ::strerror(errno));
194 }
195 break;
196 } else {
197 FI_HILOGE("EOF happened");
198 ReleaseSession(source.GetFd());
199 break;
200 }
201 } while (numRead == sizeof(buf));
202 }
203
ReleaseSession(int32_t fd)204 void SocketSessionManager::ReleaseSession(int32_t fd)
205 {
206 CALL_DEBUG_ENTER;
207 std::lock_guard<std::recursive_mutex> guard(mutex_);
208 if (auto iter = sessions_.find(fd); iter != sessions_.end()) {
209 auto session = iter->second;
210 sessions_.erase(iter);
211
212 if (session != nullptr) {
213 epollMgr_.Remove(session);
214 NotifySessionDeleted(session);
215 }
216 }
217 DumpSession("DelSession");
218 }
219
DeleteCollaborationServiceByName()220 void SocketSessionManager::DeleteCollaborationServiceByName()
221 {
222 CALL_DEBUG_ENTER;
223 std::lock_guard<std::recursive_mutex> guard(mutex_);
224 auto iter = std::find_if(sessions_.cbegin(), sessions_.cend(),
225 [](const auto &item) {
226 return ((item.second != nullptr) && (item.second->GetProgramName() == "collaboration_service"));
227 });
228 if (iter != sessions_.end()) {
229 auto session = iter->second;
230 if (session != nullptr) {
231 epollMgr_.Remove(session);
232 NotifySessionDeleted(session);
233 }
234 sessions_.erase(iter);
235 }
236 DumpSession("DelSession");
237 }
238
ReleaseSessionByPid(int32_t pid)239 void SocketSessionManager::ReleaseSessionByPid(int32_t pid)
240 {
241 CALL_DEBUG_ENTER;
242 std::lock_guard<std::recursive_mutex> guard(mutex_);
243 auto iter = std::find_if(sessions_.cbegin(), sessions_.cend(),
244 [pid](const auto &item) {
245 return ((item.second != nullptr) && (item.second->GetPid() == pid));
246 });
247 if (iter != sessions_.end()) {
248 auto session = iter->second;
249 if (session != nullptr) {
250 epollMgr_.Remove(session);
251 NotifySessionDeleted(session);
252 }
253 sessions_.erase(iter);
254 }
255 DumpSession("DelSession");
256 }
257
GetAppMgr()258 sptr<AppExecFwk::IAppMgr> SocketSessionManager::GetAppMgr()
259 {
260 CALL_INFO_TRACE;
261 auto saMgr = SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
262 CHKPP(saMgr);
263 auto appMgrObj = saMgr->GetSystemAbility(APP_MGR_SERVICE_ID);
264 CHKPP(appMgrObj);
265 return iface_cast<AppExecFwk::IAppMgr>(appMgrObj);
266 }
267
FindSession(int32_t fd) const268 std::shared_ptr<SocketSession> SocketSessionManager::FindSession(int32_t fd) const
269 {
270 std::lock_guard<std::recursive_mutex> guard(mutex_);
271 auto iter = sessions_.find(fd);
272 return (iter != sessions_.cend() ? iter->second : nullptr);
273 }
274
DumpSession(const std::string &title) const275 void SocketSessionManager::DumpSession(const std::string &title) const
276 {
277 FI_HILOGD("in %{public}s:%{public}s", __func__, title.c_str());
278 std::lock_guard<std::recursive_mutex> guard(mutex_);
279 int32_t i = 0;
280
281 for (auto &[_, session] : sessions_) {
282 CHKPC(session);
283 FI_HILOGI("%{public}d, %{public}s", i, session->ToString().c_str());
284 i++;
285 }
286 }
287
AddSession(std::shared_ptr<SocketSession> session)288 bool SocketSessionManager::AddSession(std::shared_ptr<SocketSession> session)
289 {
290 CALL_DEBUG_ENTER;
291 std::lock_guard<std::recursive_mutex> guard(mutex_);
292 CHKPF(session);
293 if (sessions_.size() >= MAX_SESSION_ALARM) {
294 FI_HILOGE("The number of connections exceeds limit(%{public}zu)", MAX_SESSION_ALARM);
295 return false;
296 }
297 auto [iter, inserted] = sessions_.emplace(session->GetFd(), session);
298 if (!inserted) {
299 FI_HILOGE("Session(%{public}d) has been recorded", session->GetFd());
300 return false;
301 }
302 if (!epollMgr_.Add(session)) {
303 FI_HILOGE("Failed to listening on session(%{public}d)", session->GetFd());
304 sessions_.erase(iter);
305 return false;
306 }
307 DumpSession("AddSession");
308 return true;
309 }
310
AddSessionDeletedCallback(int32_t pid, std::function<void(SocketSessionPtr)> callback)311 void SocketSessionManager::AddSessionDeletedCallback(int32_t pid, std::function<void(SocketSessionPtr)> callback)
312 {
313 std::lock_guard<std::recursive_mutex> guard(mutex_);
314 if (callback == nullptr) {
315 FI_HILOGE("Callback is none");
316 return;
317 }
318 auto [_, inserted] = callbacks_.emplace(pid, callback);
319 if (!inserted) {
320 FI_HILOGW("Duplication of session-lost callback for (%{public}d)", pid);
321 }
322 FI_HILOGI("Start watching socket-session(%{public}d)", pid);
323 }
324
RemoveSessionDeletedCallback(int32_t pid)325 void SocketSessionManager::RemoveSessionDeletedCallback(int32_t pid)
326 {
327 FI_HILOGI("Stop watching socket-session(%{public}d)", pid);
328 std::lock_guard<std::recursive_mutex> guard(mutex_);
329 callbacks_.erase(pid);
330 }
331
NotifySessionDeleted(std::shared_ptr<SocketSession> session)332 void SocketSessionManager::NotifySessionDeleted(std::shared_ptr<SocketSession> session)
333 {
334 FI_HILOGI("Session lost, pid:%{public}d", session->GetPid());
335 if (auto iter = callbacks_.find(session->GetPid()); iter != callbacks_.end()) {
336 if (iter->second) {
337 iter->second(session);
338 }
339 callbacks_.erase(iter);
340 }
341 }
342 } // namespace DeviceStatus
343 } // namespace Msdp
344 } // namespace OHOS
345