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_client.h"
17 #include "i_media_service.h"
18 #include "media_log.h"
19 #include "media_errors.h"
20 #include "scope_guard.h"
21 
22 namespace {
23 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_PLAYER, "MonitorClient" };
24 }
25 
26 namespace OHOS {
27 namespace Media {
28 std::mutex MonitorClient::instanceMutex_;
29 std::shared_ptr<MonitorClient> MonitorClient::monitorClient_ = std::make_shared<MonitorClient>();
30 MonitorClient::Destroy MonitorClient::destroy_;
31 
32 constexpr uint8_t TIME_INTERVAL = 1; // Heartbeat once per second
33 
MonitorClient()34 MonitorClient::MonitorClient()
35 {
36     MEDIA_LOGI("Instances create");
37 }
38 
~MonitorClient()39 MonitorClient::~MonitorClient()
40 {
41     MEDIA_LOGI("Instances destroy");
42     clientDestroy_ = true;
43     std::lock_guard<std::mutex> threadLock(thredMutex_);
44     if (clickThread_ != nullptr) {
45         MEDIA_LOGI("clear monitor client thread");
46         if (clickThread_->joinable()) {
47             clickCond_.notify_all();
48             clickThread_->join();
49         }
50         clickThread_.reset();
51         clickThread_ = nullptr;
52     }
53     MEDIA_LOGI("Instances Destroy end");
54 }
55 
GetInstance()56 std::shared_ptr<MonitorClient> MonitorClient::GetInstance()
57 {
58     std::lock_guard<std::mutex> lock(instanceMutex_);
59     return monitorClient_;
60 }
61 
IsVaildProxy()62 bool MonitorClient::IsVaildProxy()
63 {
64     {
65         std::lock_guard<std::mutex> lock(mutex_);
66         if (!isVaildProxy_) {
67             monitorProxy_ = nullptr;
68         }
69     }
70 
71     if (monitorProxy_ == nullptr) {
72         monitorProxy_ = MediaServiceFactory::GetInstance().GetMonitorProxy();
73         CHECK_AND_RETURN_RET_LOG(monitorProxy_ != nullptr, false, "monitorProxy_ is nullptr!");
74         std::lock_guard<std::mutex> lock(mutex_);
75         isVaildProxy_ = true;
76     }
77 
78     return true;
79 }
80 
StartClick(MonitorClientObject * obj)81 int32_t MonitorClient::StartClick(MonitorClientObject *obj)
82 {
83     MEDIA_LOGI("0x%{public}06" PRIXPTR " StartClick", FAKE_POINTER(obj));
84     {
85         std::lock_guard<std::mutex> lock(mutex_);
86         CHECK_AND_RETURN_RET_LOG(objSet_.count(obj) == 0, MSERR_OK, "It has already been activated");
87         objSet_.insert(obj);
88         if (threadRunning_) {
89             return MSERR_OK;
90         }
91         threadRunning_ = true;
92     }
93 
94     std::lock_guard<std::mutex> threadLock(thredMutex_);
95     // The original thread has already exited. Need to recycle resources
96     if (clickThread_ != nullptr) {
97         if (clickThread_->joinable()) {
98             clickThread_->join();
99         }
100         clickThread_.reset();
101         clickThread_ = nullptr;
102     }
103 
104     // Start Thread
105     CHECK_AND_RETURN_RET(!clientDestroy_, MSERR_OK);
106     clickThread_ = std::make_unique<std::thread>([this] () -> void { this->ClickThreadCtrl(); });
107 
108     return MSERR_OK;
109 }
110 
StopClick(MonitorClientObject * obj)111 int32_t MonitorClient::StopClick(MonitorClientObject *obj)
112 {
113     MEDIA_LOGI("0x%{public}06" PRIXPTR " StopClick", FAKE_POINTER(obj));
114     std::lock_guard<std::mutex> lock(mutex_);
115     CHECK_AND_RETURN_RET_LOG(objSet_.count(obj), MSERR_OK, "Not started");
116 
117     objSet_.erase(obj);
118     if (objSet_.empty()) {
119         clickCond_.notify_all();
120     }
121 
122     return MSERR_OK;
123 }
124 
MediaServerDied()125 void MonitorClient::MediaServerDied()
126 {
127     MEDIA_LOGI("MediaServerDied");
128     std::lock_guard<std::mutex> lock(mutex_);
129     objSet_.clear();
130     isVaildProxy_ = false;
131     clickCond_.notify_all();
132 }
133 
ClickThread()134 void MonitorClient::ClickThread()
135 {
136     pthread_setname_np(pthread_self(), "OS_MonitorClick");
137     MEDIA_LOGD("ClickThread start");
138 
139     CHECK_AND_RETURN_LOG(IsVaildProxy(), "Proxy is invaild!");
140     CHECK_AND_RETURN_LOG(monitorProxy_->EnableMonitor() == MSERR_OK, "failed to EnableMonitor");
141 
142     while (true) {
143         {
144             std::unique_lock<std::mutex> lock(mutex_);
145             clickCond_.wait_for(lock, std::chrono::seconds(TIME_INTERVAL), [this] {
146                 return objSet_.empty() || !isVaildProxy_ || clientDestroy_;
147             });
148 
149             CHECK_AND_RETURN_LOG(!clientDestroy_, "clientDestroy, Normal exit");
150 
151             if (objSet_.empty()) {
152                 MEDIA_LOGI("0x%{public}06" PRIXPTR " objSet empty.", FAKE_POINTER(this));
153                 break;
154             }
155             if (!isVaildProxy_) {
156                 monitorProxy_ = nullptr;
157                 MEDIA_LOGI("Proxy is invaild.");
158                 return;
159             }
160         }
161         CHECK_AND_RETURN_LOG(monitorProxy_ != nullptr, "monitorProxy_ is nullptr!");
162         CHECK_AND_CONTINUE(monitorProxy_->Click() == MSERR_OK);
163     }
164 
165     CHECK_AND_RETURN_LOG(IsVaildProxy(), "Proxy is invaild!");
166     CHECK_AND_RETURN_LOG(monitorProxy_->DisableMonitor() == MSERR_OK, "failed to DisableMonitor");
167     MEDIA_LOGI("0x%{public}06" PRIXPTR " ClickThread End", FAKE_POINTER(this));
168 }
169 
ClickThreadCtrl()170 void MonitorClient::ClickThreadCtrl()
171 {
172     while (true) {
173         ClickThread();
174         std::unique_lock<std::mutex> lock(mutex_);
175         clickCond_.wait_for(lock, std::chrono::seconds(TIME_INTERVAL), [this] {
176             return objSet_.empty() || clientDestroy_;
177         });
178         if (objSet_.empty() || clientDestroy_) {
179             threadRunning_ = false;
180             MEDIA_LOGI("objSetsize %{public}zu, clientDestroy %{public}d.",
181                 objSet_.size(), clientDestroy_.load());
182             return;
183         }
184     }
185 }
186 
~Destroy()187 MonitorClient::Destroy::~Destroy()
188 {
189     MEDIA_LOGI("MonitorClient Destroy start");
190     std::shared_ptr<MonitorClient> temp;
191     std::lock_guard<std::mutex> lock(instanceMutex_);
192     CHECK_AND_RETURN_LOG(monitorClient_ != nullptr, "MonitorClient Destroy end");
193     temp = monitorClient_;
194     monitorClient_ = nullptr;
195     MEDIA_LOGI("MonitorClient Destroy end");
196 }
197 } // namespace Media
198 } // namespace OHOS
199