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, &timestamp);
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