1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
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 "monitor_server.h"
17 #include <sys/time.h>
18 #include <string>
19 #include <unistd.h>
20 #include "media_log.h"
21 #include "media_errors.h"
22 #include "scope_guard.h"
23
24 namespace {
25 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_PLAYER, "MonitorServer" };
26 }
27
28 namespace OHOS {
29 namespace Media {
30 const int32_t MONITOR_TIMEMS = 15000; // IPC disconnection limit 15000 ms.
31 constexpr uint64_t SEC_TO_MS = 1000;
32 constexpr uint64_t NS_TO_MS = 1000000;
33
MonitorServer()34 MonitorServer::MonitorServer()
35 {
36 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances create", FAKE_POINTER(this));
37 }
38
~MonitorServer()39 MonitorServer::~MonitorServer()
40 {
41 MEDIA_LOGI("0x%{public}06" PRIXPTR " Instances destroy", FAKE_POINTER(this));
42 threadRunning_ = false;
43 std::lock_guard<std::mutex> threadLock(thredMutex_);
44 if (thread_ != nullptr) {
45 if (thread_->joinable()) {
46 cond_.notify_all();
47 thread_->join();
48 }
49 thread_.reset();
50 thread_ = nullptr;
51 }
52 objListMap_.clear();
53 MEDIA_LOGI("Instances destroy end");
54 }
55
GetInstance()56 MonitorServer &MonitorServer::GetInstance()
57 {
58 static MonitorServer instance;
59 return instance;
60 }
61
Dump(int32_t fd,bool needDetail)62 int32_t MonitorServer::Dump(int32_t fd, bool needDetail)
63 {
64 (void)needDetail;
65 std::unique_lock<std::mutex> lock(mutex_);
66 std::string dumpString = "------------------Monitor------------------\n";
67 int32_t i = 0;
68 for (auto it = objListMap_.begin(); it != objListMap_.end(); it++) {
69 dumpString += "-----Instance #:" + std::to_string(i) + " pid = " + std::to_string(it->first);
70 dumpString += " objsize = " + std::to_string(it->second.size());
71
72 auto timeInfoIt = timesMap_.find(it->first);
73 if (timeInfoIt != timesMap_.end()) {
74 dumpString += " remainder = " + std::to_string(timeInfoIt->second.time) + "ms";
75 dumpString += " alarmed = " + std::to_string(timeInfoIt->second.alarmed);
76 } else {
77 dumpString += " DisableMonitor";
78 }
79
80 dumpString += "\n";
81 i++;
82 }
83
84 if (fd != -1) {
85 write(fd, dumpString.c_str(), dumpString.size());
86 dumpString.clear();
87 }
88 return MSERR_OK;
89 }
90
Click(int32_t pid)91 int32_t MonitorServer::Click(int32_t pid)
92 {
93 MEDIA_LOGD("Click from %{public}d", pid);
94 std::unique_lock<std::mutex> lock(mutex_);
95
96 auto timeInfoIt = timesMap_.find(pid);
97 CHECK_AND_RETURN_RET_LOG(timeInfoIt != timesMap_.end(), MSERR_OK,
98 "Process %{public}d is not in the monitoring queue!", pid);
99
100 timeInfoIt->second.time = MONITOR_TIMEMS;
101 timeInfoIt->second.triggerFlag = true;
102
103 // Wake up thread retiming wait
104 waitingAgain_ = true;
105 cond_.notify_all();
106 return MSERR_OK;
107 }
108
EnableMonitor(int32_t pid)109 int32_t MonitorServer::EnableMonitor(int32_t pid)
110 {
111 MEDIA_LOGI("EnableMonitor from %{public}d", pid);
112 {
113 std::unique_lock<std::mutex> lock(mutex_);
114 CHECK_AND_RETURN_RET_LOG(timesMap_.find(pid) == timesMap_.end(), MSERR_OK,
115 "Process %{public}d is already in the monitoring queue!", pid);
116
117 timesMap_.insert(std::pair<int32_t, TimeInfo>(pid, TimeInfo(MONITOR_TIMEMS, true)));
118
119 // Wake up thread retiming wait
120 waitingAgain_ = true;
121 cond_.notify_all();
122 if (threadRunning_) {
123 return MSERR_OK;
124 }
125 threadRunning_ = true;
126 }
127
128 std::lock_guard<std::mutex> threadLock(thredMutex_);
129 // The original thread has already exited. Need to recycle resources
130 if (thread_ != nullptr) {
131 if (thread_->joinable()) {
132 thread_->join();
133 }
134 thread_.reset();
135 thread_ = nullptr;
136 }
137
138 // Start Thread
139 thread_ = std::make_unique<std::thread>([this] () -> void { this->MonitorThread(); });
140
141 return MSERR_OK;
142 }
143
DisableMonitor(int32_t pid)144 int32_t MonitorServer::DisableMonitor(int32_t pid)
145 {
146 MEDIA_LOGI("DisableMonitor from %{public}d", pid);
147 std::unique_lock<std::mutex> lock(mutex_);
148
149 CHECK_AND_RETURN_RET_LOG(timesMap_.find(pid) != timesMap_.end(), MSERR_OK,
150 "Process %{public}d is not in the monitoring queue!", pid);
151
152 timesMap_.erase(pid);
153
154 // Exit Thread
155 if (timesMap_.empty()) {
156 cond_.notify_all();
157 }
158
159 return MSERR_OK;
160 }
161
RegisterObj(int32_t pid,wptr<MonitorServerObject> obj)162 int32_t MonitorServer::RegisterObj(int32_t pid, wptr<MonitorServerObject> obj)
163 {
164 MEDIA_LOGI("pid %{public}d obj 0x%{public}06" PRIXPTR " Register", pid, FAKE_POINTER(obj.GetRefPtr()));
165 std::unique_lock<std::mutex> lock(mutex_);
166
167 auto objListIt = objListMap_.find(pid);
168 if (objListIt != objListMap_.end()) {
169 MEDIA_LOGI("The pid %{public}d has already been registered", pid);
170 auto objIt = std::find(objListIt->second.begin(), objListIt->second.end(), obj);
171 CHECK_AND_RETURN_RET_LOG(objIt == objListIt->second.end(), MSERR_OK, "The obj has already been registered");
172
173 // Add obj to monitoring queue
174 objListIt->second.push_back(obj);
175 return MSERR_OK;
176 }
177
178 // Add pid and obj to the monitoring queue
179 std::list<wptr<MonitorServerObject>> objList;
180 objList.push_back(obj);
181 objListMap_[pid] = objList;
182
183 return MSERR_OK;
184 }
185
CancellationObj(int32_t pid,wptr<MonitorServerObject> obj)186 int32_t MonitorServer::CancellationObj(int32_t pid, wptr<MonitorServerObject> obj)
187 {
188 MEDIA_LOGI("pid %{public}d obj 0x%{public}06" PRIXPTR " Cancellation", pid, FAKE_POINTER(obj.GetRefPtr()));
189 std::unique_lock<std::mutex> lock(mutex_);
190
191 auto objListIt = objListMap_.find(pid);
192 CHECK_AND_RETURN_RET_LOG(objListIt != objListMap_.end(), MSERR_OK, "This pid has not been registered");
193
194 auto objIt = std::find(objListIt->second.begin(), objListIt->second.end(), obj);
195 CHECK_AND_RETURN_RET_LOG(objIt != objListIt->second.end(), MSERR_OK, "The obj has not been registered");
196
197 // Remove obj from monitoring queue
198 objListIt->second.erase(objIt);
199
200 // Remove pid from monitoring queue
201 if (objListIt->second.empty()) {
202 objListMap_.erase(objListIt);
203 }
204
205 return MSERR_OK;
206 }
207
OnClientDie(int32_t pid)208 int32_t MonitorServer::OnClientDie(int32_t pid)
209 {
210 MEDIA_LOGI("pid %{public}d OnClientDie", pid);
211 std::unique_lock<std::mutex> lock(mutex_);
212 objListMap_.erase(pid);
213 timesMap_.erase(pid);
214
215 // Exit Thread
216 if (timesMap_.empty()) {
217 cond_.notify_all();
218 }
219
220 return MSERR_OK;
221 }
222
GetTimeMS()223 uint64_t MonitorServer::GetTimeMS()
224 {
225 struct timespec timestamp = {0, 0};
226 clock_gettime(CLOCK_MONOTONIC, ×tamp);
227 return timestamp.tv_sec * SEC_TO_MS + timestamp.tv_nsec / NS_TO_MS;
228 }
229
ObjCtrl(std::list<wptr<MonitorServerObject>> & recoveryList,std::list<wptr<MonitorServerObject>> & abnormalList)230 int32_t MonitorServer::ObjCtrl(std::list<wptr<MonitorServerObject>> &recoveryList,
231 std::list<wptr<MonitorServerObject>> &abnormalList)
232 {
233 for (auto objIt = recoveryList.begin(); objIt != recoveryList.end(); objIt++) {
234 sptr<MonitorServerObject> obj = objIt->promote();
235 CHECK_AND_CONTINUE(obj != nullptr);
236 (void)obj->IpcRecovery(true);
237 }
238
239 for (auto objIt = abnormalList.begin(); objIt != abnormalList.end(); objIt++) {
240 sptr<MonitorServerObject> obj = objIt->promote();
241 CHECK_AND_CONTINUE(obj != nullptr);
242 (void)obj->IpcAbnormality();
243 }
244
245 return MSERR_OK;
246 }
247
GetObjListByPid(int32_t pid,std::list<wptr<MonitorServerObject>> & list)248 int32_t MonitorServer::GetObjListByPid(int32_t pid, std::list<wptr<MonitorServerObject>> &list)
249 {
250 auto objListIt = objListMap_.find(pid);
251 CHECK_AND_RETURN_RET_LOG(objListIt != objListMap_.end(), MSERR_OK,
252 "The pid %{public}d is not in the objList", pid);
253
254 for (auto objIt = objListIt->second.begin(); objIt != objListIt->second.end(); objIt++) {
255 list.push_back(*objIt);
256 }
257
258 return MSERR_OK;
259 }
260
GetWaitTime()261 int32_t MonitorServer::GetWaitTime()
262 {
263 int32_t minTime = MONITOR_TIMEMS;
264 for (auto timeInfoIt = timesMap_.begin(); timeInfoIt != timesMap_.end(); timeInfoIt++) {
265 if (timeInfoIt->second.time > 0 && timeInfoIt->second.time < minTime) {
266 minTime = timeInfoIt->second.time;
267 }
268 }
269 return minTime;
270 }
271
MonitorThread()272 void MonitorServer::MonitorThread()
273 {
274 uint64_t timeStart;
275 int32_t waitTime;
276 MEDIA_LOGI("MonitorThread start");
277 pthread_setname_np(pthread_self(), "MonitorServer");
278
279 while (true) {
280 std::list<wptr<MonitorServerObject>> recoveryList;
281 std::list<wptr<MonitorServerObject>> abnormalList;
282 {
283 std::unique_lock<std::mutex> lock(mutex_);
284
285 timeStart = GetTimeMS();
286 cond_.wait_for(lock, std::chrono::milliseconds(GetWaitTime()), [this] {
287 return timesMap_.empty() || waitingAgain_ || !threadRunning_;
288 });
289
290 if (!threadRunning_) {
291 MEDIA_LOGI("Stop running and exit loop.");
292 break;
293 }
294
295 if (timesMap_.empty()) {
296 MEDIA_LOGI("TimesMap empty. MonitorThread Stop.");
297 threadRunning_ = false;
298 break;
299 }
300
301 waitTime = static_cast<int32_t>(GetTimeMS() - timeStart);
302
303 for (auto it = timesMap_.begin(); it != timesMap_.end(); it++) {
304 MEDIA_LOGD("pid %{public}d, waitTime %{public}d, timeout %{public}d, trigger %{public}d",
305 it->first, waitTime, it->second.time, it->second.triggerFlag);
306 if (it->second.triggerFlag == true) {
307 it->second.triggerFlag = false;
308 } else {
309 it->second.time -= waitTime;
310 }
311
312 if (it->second.alarmed == true && it->second.time > 0) {
313 it->second.alarmed = false;
314 (void)GetObjListByPid(it->first, recoveryList);
315 MEDIA_LOGW("%{public}d Recovery", it->first);
316 }
317
318 if (it->second.time <= 0 && it->second.alarmed == false) {
319 it->second.alarmed = true;
320 (void)GetObjListByPid(it->first, abnormalList);
321 MEDIA_LOGW("%{public}d Abnormality", it->first);
322 }
323 }
324 waitingAgain_ = false;
325 }
326 (void)ObjCtrl(recoveryList, abnormalList);
327 }
328 MEDIA_LOGI("MonitorThread end");
329 }
330 } // namespace Media
331 } // namespace OHOS
332