• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifndef LOG_TAG
16 #define LOG_TAG "AudioSchedule"
17 #endif
18 
19 #include "audio_schedule.h"
20 #include "audio_schedule_guard.h"
21 
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <cstring>
25 #include <unordered_map>
26 #include <set>
27 
28 #ifdef RESSCHE_ENABLE
29 #include "res_type.h"
30 #include "res_sched_client.h"
31 #endif
32 #include "qos.h"
33 #include "concurrent_task_client.h"
34 
35 #include "audio_utils.h"
36 #include "audio_common_log.h"
37 
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41 
42 using namespace OHOS::AudioStandard;
43 
44 #ifdef RESSCHE_ENABLE
45 const uint32_t AUDIO_QOS_LEVEL = 7;
46 const int32_t DEFAULT_QOS_LEVEL = -1;
47 const uint32_t REPORTDATA_TIMEOUT = 8;
48 static std::mutex g_rssMutex;
49 static std::set<uint32_t> g_tidToReport = {};
50 constexpr uint32_t g_type = OHOS::ResourceSchedule::ResType::RES_TYPE_THREAD_QOS_CHANGE;
51 constexpr int64_t g_value = 0;
52 constexpr int32_t AUDIO_PROC_QOS_TABLE = 7;
53 
ConfigPayload(pid_t pid,pid_t tid,const char * bundleName,int32_t qosLevel,std::unordered_map<std::string,std::string> & mapPayload)54 void ConfigPayload(pid_t pid, pid_t tid, const char *bundleName, int32_t qosLevel,
55     std::unordered_map<std::string, std::string> &mapPayload)
56 {
57     std::string strBundleName = bundleName;
58     std::string strPid = std::to_string(pid);
59     std::string strTid = std::to_string(tid);
60     std::string strQos = std::to_string(qosLevel);
61     mapPayload["pid"] = strPid;
62     mapPayload[strTid] = strQos;
63     mapPayload["bundleName"] = strBundleName;
64 }
65 
ScheduleReportDataWithQosLevel(pid_t pid,pid_t tid,const char * bundleName,int32_t qosLevel)66 void ScheduleReportDataWithQosLevel(pid_t pid, pid_t tid, const char *bundleName, int32_t qosLevel)
67 {
68     AudioXCollie audioXcollie("RSS::ReportData with qos level + " + std::to_string(qosLevel) +
69         ", pid " + std::to_string(pid) + ", tid " + std::to_string(tid), REPORTDATA_TIMEOUT,
70          nullptr, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
71     AUDIO_INFO_LOG("Report tid %{public}u to qosLeve %{public}d", tid, qosLevel);
72     std::unordered_map<std::string, std::string> mapPayload;
73     ConfigPayload(pid, tid, bundleName, qosLevel, mapPayload);
74     OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(g_type, g_value, mapPayload);
75 }
76 
ScheduleReportData(pid_t pid,pid_t tid,const char * bundleName)77 void ScheduleReportData(pid_t pid, pid_t tid, const char *bundleName)
78 {
79     AudioXCollie audioXcollie("RSS::ReportData with qos level 7, pid " + std::to_string(pid) +
80         ", tid " + std::to_string(tid), REPORTDATA_TIMEOUT,
81          nullptr, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
82     Trace trace ("Rss::ReportData with qos level 7");
83     AUDIO_INFO_LOG("Report tid %{public}u", tid);
84     std::unordered_map<std::string, std::string> mapPayload;
85     ConfigPayload(pid, tid, bundleName, AUDIO_QOS_LEVEL, mapPayload);
86     OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(g_type, g_value, mapPayload);
87 }
88 
UnscheduleReportData(pid_t pid,pid_t tid,const char * bundleName)89 void UnscheduleReportData(pid_t pid, pid_t tid, const char* bundleName)
90 {
91     AudioXCollie audioXcollie("RSS::ReportData with qos level -1, pid " + std::to_string(pid) +
92         ", tid " + std::to_string(tid), REPORTDATA_TIMEOUT,
93          nullptr, nullptr, AUDIO_XCOLLIE_FLAG_LOG | AUDIO_XCOLLIE_FLAG_RECOVERY);
94     Trace trace ("Rss::ReportData with qos level -1");
95     std::unordered_map<std::string, std::string> mapPayload;
96     ConfigPayload(pid, tid, bundleName, DEFAULT_QOS_LEVEL, mapPayload);
97     OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(g_type, g_value, mapPayload);
98 }
99 
UnscheduleThreadInServer(pid_t pid,pid_t tid)100 void UnscheduleThreadInServer(pid_t pid, pid_t tid)
101 {
102     std::lock_guard<std::mutex> lock(g_rssMutex);
103     if (g_tidToReport.find(tid) != g_tidToReport.end()) {
104         AUDIO_INFO_LOG("Remove tid in server %{public}u", tid);
105         g_tidToReport.erase(tid);
106     }
107     UnscheduleReportData(pid, tid, "audio_server");
108 }
109 
ScheduleThreadInServer(pid_t pid,pid_t tid)110 void ScheduleThreadInServer(pid_t pid, pid_t tid)
111 {
112     std::lock_guard<std::mutex> lock(g_rssMutex);
113     if (g_tidToReport.find(tid) == g_tidToReport.end()) {
114         AUDIO_INFO_LOG("Add tid in server %{public}u", tid);
115         g_tidToReport.insert(tid);
116     }
117     ScheduleReportData(pid, tid, "audio_server");
118 }
119 
SetProcessDataThreadPriority(int32_t priority)120 void SetProcessDataThreadPriority(int32_t priority)
121 {
122     struct sched_param param = {0};
123     // setPriority = 50 + priority
124     param.sched_priority = priority;
125     int32_t res = sched_setscheduler(0, SCHED_FIFO | SCHED_RESET_ON_FORK, &param);
126     if (res != 0) {
127         AUDIO_ERR_LOG("Set thread 50 + %{public}d priority fail : %{public}d", param.sched_priority, res);
128         return;
129     }
130     AUDIO_INFO_LOG("Set thread 50 + %{public}d priority success", param.sched_priority);
131     return;
132 }
133 
ResetProcessDataThreadPriority()134 void ResetProcessDataThreadPriority()
135 {
136     struct sched_param param = {0};
137     param.sched_priority = 0;
138     int32_t res = sched_setscheduler(0, SCHED_OTHER, &param);
139     if (res != 0) {
140         AUDIO_ERR_LOG("Reset thread priority fail : %{public}d", res);
141         return;
142     }
143     AUDIO_INFO_LOG("Reset thread priority success");
144     return;
145 }
146 
OnAddResSchedService(uint32_t audioServerPid)147 void OnAddResSchedService(uint32_t audioServerPid)
148 {
149     std::lock_guard<std::mutex> lock(g_rssMutex);
150     for (auto tid : g_tidToReport) {
151         AUDIO_INFO_LOG("On add rss, report %{public}u", tid);
152         ScheduleReportData(audioServerPid, tid, "audio_server");
153     }
154 }
155 
SetEndpointThreadPriority()156 bool SetEndpointThreadPriority()
157 {
158     Trace trace("SetEndpointThreadPriority");
159     bool res = false;
160     std::unordered_map<std::string, std::string> payload;
161     payload["groupId"] = std::to_string(AUDIO_PROC_QOS_TABLE);
162     payload["pid"] = std::to_string(getpid());
163     OHOS::ConcurrentTask::ConcurrentTaskClient::GetInstance().RequestAuth(payload);
164     int32_t ret = OHOS::QOS::SetThreadQos(OHOS::QOS::QosLevel::QOS_KEY_BACKGROUND);
165     if (ret == 0) {
166         res = true;
167     }
168     AUDIO_INFO_LOG("set thread qos %{public}s", ret ? "failed" : "success");
169     return res;
170 }
171 
ResetEndpointThreadPriority()172 bool ResetEndpointThreadPriority()
173 {
174     struct sched_param param = {0};
175     param.sched_priority = 0;
176     auto res = sched_setscheduler(0, SCHED_OTHER, &param);
177     if (res != 0) {
178         AUDIO_ERR_LOG("Reset thread priority fail : %{public}d", res);
179         return false;
180     }
181     AUDIO_INFO_LOG("Reset thread priority success");
182     return true;
183 };
184 #else
ScheduleReportData(uint32_t,uint32_t,const char *)185 void ScheduleReportData(uint32_t /* pid */, uint32_t /* tid */, const char* /* bundleName*/) {};
ScheduleThreadInServer(pid_t pid,pid_t tid)186 void ScheduleThreadInServer(pid_t pid, pid_t tid) {};
UnscheduleThreadInServer(pid_t tid)187 void UnscheduleThreadInServer(pid_t tid) {};
OnAddResSchedService(uint32_t audioServerPid)188 void OnAddResSchedService(uint32_t audioServerPid) {};
SetProcessDataThreadPriority(int32_t priority)189 void SetProcessDataThreadPriority(int32_t priority) {};
ResetProcessDataThreadPriority()190 void ResetProcessDataThreadPriority() {};
UnscheduleReportData(uint32_t,uint32_t,const char *)191 void UnscheduleReportData(uint32_t /* pid */, uint32_t /* tid */, const char* /* bundleName*/) {};
SetEndpointThreadPriority()192 bool SetEndpointThreadPriority() { return false; };
ResetEndpointThreadPriority()193 bool ResetEndpointThreadPriority() { return false; };
194 #endif
195 
196 #ifdef __cplusplus
197 }
198 #endif
199 
200 namespace OHOS {
201 namespace AudioStandard {
202 namespace {
203 static constexpr unsigned int WAIT_TIMEOUT_SECONDS = 5;
204 }
205 std::map<std::pair<pid_t, pid_t>,
206     std::weak_ptr<SharedAudioScheduleGuard>> SharedAudioScheduleGuard::guardMap_;
207 std::mutex SharedAudioScheduleGuard::mutex_;
208 std::condition_variable SharedAudioScheduleGuard::cv_;
209 
AudioScheduleGuard(pid_t pid,pid_t tid,const std::string & bundleName)210 AudioScheduleGuard::AudioScheduleGuard(pid_t pid, pid_t tid, const std::string &bundleName)
211     : pid_(pid), tid_(tid), bundleName_(bundleName)
212 {
213     ScheduleReportData(pid, tid, bundleName.c_str());
214     isReported_ = true;
215 }
216 
AudioScheduleGuard(AudioScheduleGuard && audioScheduleGuard)217 AudioScheduleGuard::AudioScheduleGuard(AudioScheduleGuard&& audioScheduleGuard)
218     : pid_(audioScheduleGuard.pid_), tid_(audioScheduleGuard.tid_),
219     bundleName_(std::move(audioScheduleGuard.bundleName_)), isReported_(audioScheduleGuard.isReported_)
220 {
221     audioScheduleGuard.isReported_ = false;
222 }
223 
224 bool AudioScheduleGuard::operator==(const AudioScheduleGuard&) const = default;
225 
~AudioScheduleGuard()226 AudioScheduleGuard::~AudioScheduleGuard()
227 {
228     if (isReported_) {
229         UnscheduleReportData(pid_, tid_, bundleName_.c_str());
230     }
231 }
232 
Create(pid_t pid,pid_t tid,const std::string & bundleName)233 std::shared_ptr<SharedAudioScheduleGuard> SharedAudioScheduleGuard::Create(pid_t pid, pid_t tid,
234     const std::string &bundleName)
235 {
236     std::shared_ptr<SharedAudioScheduleGuard> sharedGuard = nullptr;
237     std::unique_lock lock(mutex_);
238     bool isTimeout = !cv_.wait_for(lock, std::chrono::seconds(WAIT_TIMEOUT_SECONDS), [pid, tid, &sharedGuard] () {
239         if (guardMap_.contains({pid, tid})) {
240             sharedGuard = guardMap_.at({pid, tid}).lock();
241             if (sharedGuard != nullptr) {
242                 return true;
243             }
244             AUDIO_INFO_LOG("wait");
245             // if contains but sharedGuard is null, wait last object destroy.
246             return false;
247         } else {
248             return true;
249         }
250     });
251     CHECK_AND_RETURN_RET_LOG(!isTimeout, nullptr, "timeout");
252 
253     if (sharedGuard) {
254         AUDIO_INFO_LOG("ret exist obj");
255         return sharedGuard;
256     }
257 
258     if (!guardMap_.contains({pid, tid})) {
259         sharedGuard = std::make_shared<SharedAudioScheduleGuard>(pid, tid, bundleName);
260         CHECK_AND_RETURN_RET_LOG(sharedGuard, nullptr, "no mem");
261         guardMap_.insert({{pid, tid}, sharedGuard});
262         AUDIO_INFO_LOG("ret new obj");
263         return sharedGuard;
264     }
265 
266     AUDIO_ERR_LOG("unknow err");
267     return nullptr;
268 }
269 
~SharedAudioScheduleGuard()270 SharedAudioScheduleGuard::~SharedAudioScheduleGuard()
271 {
272     std::lock_guard lock(mutex_);
273     // unreport must guard by mutex
274     AudioScheduleGuard tempGuard(std::move(guard_));
275     guardMap_.erase({pid_, tid_});
276     cv_.notify_all();
277     AUDIO_INFO_LOG("out");
278 }
279 } // namespace AudioStandard
280 } // namespace OHOS
281