• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 "AudioServerDump"
17 #endif
18 
19 #include "audio_server_dump.h"
20 #include "audio_utils.h"
21 #include "audio_service.h"
22 #include "pa_adapter_tools.h"
23 
24 using namespace std;
25 
26 namespace OHOS {
27 namespace AudioStandard {
28 
AudioServerDump()29 AudioServerDump::AudioServerDump() : mainLoop(nullptr),
30     api(nullptr),
31     context(nullptr),
32     isMainLoopStarted_(false),
33     isContextConnected_(false)
34 {
35     AUDIO_DEBUG_LOG("AudioServerDump construct");
36     InitDumpFuncMap();
37 }
38 
~AudioServerDump()39 AudioServerDump::~AudioServerDump()
40 {
41     ResetPAAudioDump();
42 }
43 
InitDumpFuncMap()44 void AudioServerDump::InitDumpFuncMap()
45 {
46     dumpFuncMap[u"-h"] = &AudioServerDump::HelpInfoDump;
47     dumpFuncMap[u"-p"] = &AudioServerDump::PlaybackSinkDump;
48     dumpFuncMap[u"-r"] = &AudioServerDump::RecordSourceDump;
49     dumpFuncMap[u"-m"] = &AudioServerDump::HDFModulesDump;
50     dumpFuncMap[u"-ep"] = &AudioServerDump::PolicyHandlerDump;
51 }
52 
ResetPAAudioDump()53 void AudioServerDump::ResetPAAudioDump()
54 {
55     lock_guard<mutex> lock(ctrlMutex_);
56     if (mainLoop && (isMainLoopStarted_ == true)) {
57         pa_threaded_mainloop_stop(mainLoop);
58     }
59 
60     if (context) {
61         pa_context_set_state_callback(context, nullptr, nullptr);
62         if (isContextConnected_ == true) {
63             AUDIO_INFO_LOG("[AudioServerDump] disconnect context!");
64             pa_context_disconnect(context);
65         }
66         pa_context_unref(context);
67     }
68 
69     if (mainLoop) {
70         pa_threaded_mainloop_free(mainLoop);
71     }
72 
73     isMainLoopStarted_  = false;
74     isContextConnected_ = false;
75     mainLoop = nullptr;
76     context  = nullptr;
77     api      = nullptr;
78 }
79 
Initialize()80 int32_t AudioServerDump::Initialize()
81 {
82     mainLoop = pa_threaded_mainloop_new();
83     if (mainLoop == nullptr) {
84         return AUDIO_DUMP_INIT_ERR;
85     }
86 
87     api = pa_threaded_mainloop_get_api(mainLoop);
88     if (api == nullptr) {
89         ResetPAAudioDump();
90         return AUDIO_DUMP_INIT_ERR;
91     }
92 
93     context = pa_context_new(api, "AudioServerDump");
94     if (context == nullptr) {
95         ResetPAAudioDump();
96         return AUDIO_DUMP_INIT_ERR;
97     }
98 
99     pa_context_set_state_callback(context, PAContextStateCb, mainLoop);
100 
101     if (pa_context_connect(context, nullptr, PA_CONTEXT_NOFAIL, nullptr) < 0) {
102         int error = pa_context_errno(context);
103         AUDIO_ERR_LOG("context connect error: %{public}s", pa_strerror(error));
104         ResetPAAudioDump();
105         return AUDIO_DUMP_INIT_ERR;
106     }
107 
108     isContextConnected_ = true;
109     PaLockGuard lock(mainLoop);
110 
111     if (pa_threaded_mainloop_start(mainLoop) < 0) {
112         AUDIO_ERR_LOG("Audio Service not started");
113         ResetPAAudioDump();
114         return AUDIO_DUMP_INIT_ERR;
115     }
116 
117     isMainLoopStarted_ = true;
118     while (isMainLoopStarted_) {
119         pa_context_state_t state = pa_context_get_state(context);
120         if (state == PA_CONTEXT_READY) {
121             break;
122         }
123 
124         if (!PA_CONTEXT_IS_GOOD(state)) {
125             int error = pa_context_errno(context);
126             AUDIO_ERR_LOG("context bad state error: %{public}s", pa_strerror(error));
127             ResetPAAudioDump();
128             return AUDIO_DUMP_INIT_ERR;
129         }
130 
131         pa_threaded_mainloop_wait(mainLoop);
132     }
133 
134     return AUDIO_DUMP_SUCCESS;
135 }
136 
OnTimeOut()137 void AudioServerDump::OnTimeOut()
138 {
139     PaLockGuard lock(mainLoop);
140     pa_threaded_mainloop_signal(mainLoop, 0);
141 }
142 
IsEndWith(const std::string & mainStr,const std::string & toMatch)143 bool AudioServerDump::IsEndWith(const std::string &mainStr, const std::string &toMatch)
144 {
145     if (mainStr.size() >= toMatch.size() &&
146         mainStr.compare(mainStr.size() - toMatch.size(), toMatch.size(), toMatch) == 0) {
147         return true;
148     }
149     return false;
150 }
151 
IsValidModule(const std::string moduleName)152 bool AudioServerDump::IsValidModule(const std::string moduleName)
153 {
154     if (moduleName.rfind("fifo", 0) == SUCCESS) {
155         return false; // Module starts with fifo, Not valid module
156     }
157 
158     if (IsEndWith(moduleName, "monitor")) {
159         return false; // Module ends with monitor, Not valid module
160     }
161     return true;
162 }
163 
ServerDataDump(string & dumpString)164 void AudioServerDump::ServerDataDump(string &dumpString)
165 {
166     PlaybackSinkDump(dumpString);
167     RecordSourceDump(dumpString);
168     HDFModulesDump(dumpString);
169     PolicyHandlerDump(dumpString);
170 }
171 
ArgDataDump(std::string & dumpString,std::queue<std::u16string> & argQue)172 void AudioServerDump::ArgDataDump(std::string &dumpString, std::queue<std::u16string>& argQue)
173 {
174     dumpString += "AudioServer Data Dump:\n\n";
175     if (argQue.empty()) {
176         ServerDataDump(dumpString);
177         return;
178     }
179     while (!argQue.empty()) {
180         std::u16string para = argQue.front();
181         if (para == u"-h") {
182             dumpString.clear();
183             (this->*dumpFuncMap[para])(dumpString);
184             return;
185         } else if (dumpFuncMap.count(para) == 0) {
186             dumpString.clear();
187             AppendFormat(dumpString, "Please input correct param:\n");
188             HelpInfoDump(dumpString);
189             return;
190         } else {
191             (this->*dumpFuncMap[para])(dumpString);
192         }
193         argQue.pop();
194     }
195 }
196 
HelpInfoDump(string & dumpString)197 void AudioServerDump::HelpInfoDump(string &dumpString)
198 {
199     AppendFormat(dumpString, "usage:\n");
200     AppendFormat(dumpString, "  -h\t\t\t|help text for hidumper audio\n");
201     AppendFormat(dumpString, "  -p\t\t\t|dump pa playback streams\n");
202     AppendFormat(dumpString, "  -r\t\t\t|dump pa record streams\n");
203     AppendFormat(dumpString, "  -m\t\t\t|dump hdf input modules\n");
204     AppendFormat(dumpString, "  -ep\t\t\t|dump policyhandler info\n");
205 }
206 
AudioDataDump(string & dumpString,std::queue<std::u16string> & argQue)207 void AudioServerDump::AudioDataDump(string &dumpString, std::queue<std::u16string>& argQue)
208 {
209     if (mainLoop == nullptr || context == nullptr) {
210         AUDIO_ERR_LOG("Audio Service Not running");
211         return;
212     }
213 
214     PaLockGuard lock(mainLoop);
215     pa_operation *operation = nullptr;
216     operation = pa_context_get_sink_info_list(context,
217         AudioServerDump::PASinkInfoCallback, reinterpret_cast<void *>(this));
218 
219     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
220         pa_threaded_mainloop_wait(mainLoop);
221     }
222 
223     pa_operation_unref(operation);
224     operation = pa_context_get_sink_input_info_list(context,
225         AudioServerDump::PASinkInputInfoCallback, reinterpret_cast<void *>(this));
226 
227     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
228         pa_threaded_mainloop_wait(mainLoop);
229     }
230 
231     pa_operation_unref(operation);
232     operation = pa_context_get_source_info_list(context,
233         AudioServerDump::PASourceInfoCallback, reinterpret_cast<void *>(this));
234 
235     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
236         pa_threaded_mainloop_wait(mainLoop);
237     }
238 
239     pa_operation_unref(operation);
240     operation = pa_context_get_source_output_info_list(context,
241         AudioServerDump::PASourceOutputInfoCallback, reinterpret_cast<void *>(this));
242 
243     while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING) {
244         pa_threaded_mainloop_wait(mainLoop);
245     }
246 
247     pa_operation_unref(operation);
248 
249     ArgDataDump(dumpString, argQue);
250 
251     return;
252 }
253 
PAContextStateCb(pa_context * context,void * userdata)254 void AudioServerDump::PAContextStateCb(pa_context *context, void *userdata)
255 {
256     pa_threaded_mainloop *mainLoop = reinterpret_cast<pa_threaded_mainloop *>(userdata);
257 
258     switch (pa_context_get_state(context)) {
259         case PA_CONTEXT_READY:
260         case PA_CONTEXT_TERMINATED:
261         case PA_CONTEXT_FAILED:
262             pa_threaded_mainloop_signal(mainLoop, 0);
263             break;
264 
265         case PA_CONTEXT_UNCONNECTED:
266         case PA_CONTEXT_CONNECTING:
267         case PA_CONTEXT_AUTHORIZING:
268         case PA_CONTEXT_SETTING_NAME:
269         default:
270             break;
271     }
272     return;
273 }
274 
PASinkInfoCallback(pa_context * c,const pa_sink_info * i,int eol,void * userdata)275 void AudioServerDump::PASinkInfoCallback(pa_context *c, const pa_sink_info *i, int eol, void *userdata)
276 {
277     AudioServerDump *asDump = reinterpret_cast<AudioServerDump *>(userdata);
278     CHECK_AND_RETURN_LOG(asDump != nullptr, "Failed to get sink information");
279 
280     pa_threaded_mainloop *mainLoop = reinterpret_cast<pa_threaded_mainloop *>(asDump->mainLoop);
281 
282     CHECK_AND_RETURN_LOG(eol >= 0, "Failed to get sink information: %{public}s", pa_strerror(pa_context_errno(c)));
283 
284     if (eol) {
285         pa_threaded_mainloop_signal(mainLoop, 0);
286         return;
287     }
288 
289     SinkSourceInfo sinkInfo;
290 
291     if (i->name != nullptr) {
292         string sinkName(i->name);
293         if (IsValidModule(sinkName)) {
294             (sinkInfo.name).assign(sinkName);
295             sinkInfo.sampleSpec = i->sample_spec;
296             asDump->streamData_.sinkDevices.push_back(sinkInfo);
297         }
298     }
299 }
300 
PASinkInputInfoCallback(pa_context * c,const pa_sink_input_info * i,int eol,void * userdata)301 void AudioServerDump::PASinkInputInfoCallback(pa_context *c, const pa_sink_input_info *i, int eol, void *userdata)
302 {
303     AudioServerDump *asDump = reinterpret_cast<AudioServerDump *>(userdata);
304     CHECK_AND_RETURN_LOG(asDump != nullptr, "Failed to get sink input information");
305     pa_threaded_mainloop *mainLoop = reinterpret_cast<pa_threaded_mainloop *>(asDump->mainLoop);
306     CHECK_AND_RETURN_LOG(eol >= 0, "Failed to get sink input information: %{public}s",
307         pa_strerror(pa_context_errno(c)));
308     if (eol) {
309         pa_threaded_mainloop_signal(mainLoop, 0);
310         return;
311     }
312     InputOutputInfo sinkInputInfo;
313     sinkInputInfo.sampleSpec = i->sample_spec;
314     sinkInputInfo.corked = i->corked;
315     if (i->proplist != nullptr) {
316         const char *applicationname = pa_proplist_gets(i->proplist, "application.name");
317         const char *processid = pa_proplist_gets(i->proplist, "application.process.id");
318         const char *user = pa_proplist_gets(i->proplist, "application.process.user");
319         const char *sessionid = pa_proplist_gets(i->proplist, "stream.sessionID");
320         const char *sessionstarttime = pa_proplist_gets(i->proplist, "stream.startTime");
321         const char *privacytype = pa_proplist_gets(i->proplist, "stream.privacyType");
322         if (applicationname != nullptr) {
323             string applicationName(applicationname);
324             (sinkInputInfo.applicationName).assign(applicationName);
325         }
326         if (processid != nullptr) {
327             string processId(processid);
328             (sinkInputInfo.processId).assign(processId);
329         }
330         if (user != nullptr) {
331             struct passwd *p;
332             if ((p = getpwnam(user)) != nullptr) {
333                 sinkInputInfo.userId = uint32_t(p->pw_uid);
334             }
335         }
336         if (sessionid != nullptr) {
337             string sessionId(sessionid);
338             (sinkInputInfo.sessionId).assign(sessionId);
339         }
340         if (sessionstarttime != nullptr) {
341             string sessionStartTime(sessionstarttime);
342             (sinkInputInfo.sessionStartTime).assign(sessionStartTime);
343         }
344         if (privacytype != nullptr) {
345             string privacyType(privacytype);
346             (sinkInputInfo.privacyType).assign(privacyType);
347         }
348     }
349     asDump->streamData_.sinkInputs.push_back(sinkInputInfo);
350 }
351 
PASourceInfoCallback(pa_context * c,const pa_source_info * i,int eol,void * userdata)352 void AudioServerDump::PASourceInfoCallback(pa_context *c, const pa_source_info *i, int eol, void *userdata)
353 {
354     AudioServerDump *asDump = reinterpret_cast<AudioServerDump *>(userdata);
355     CHECK_AND_RETURN_LOG(asDump != nullptr, "Failed to get source information");
356 
357     pa_threaded_mainloop *mainLoop = reinterpret_cast<pa_threaded_mainloop *>(asDump->mainLoop);
358     CHECK_AND_RETURN_LOG(eol >= 0, "Failed to get source information: %{public}s",
359         pa_strerror(pa_context_errno(c)));
360 
361     if (eol) {
362         pa_threaded_mainloop_signal(mainLoop, 0);
363         return;
364     }
365 
366     SinkSourceInfo sourceInfo;
367 
368     if (i->name != nullptr) {
369         string sourceName(i->name);
370         if (IsValidModule(sourceName)) {
371             (sourceInfo.name).assign(sourceName);
372             sourceInfo.sampleSpec = i->sample_spec;
373             asDump->streamData_.sourceDevices.push_back(sourceInfo);
374         }
375     }
376 }
377 
PASourceOutputInfoCallback(pa_context * c,const pa_source_output_info * i,int eol,void * userdata)378 void AudioServerDump::PASourceOutputInfoCallback(pa_context *c, const pa_source_output_info *i, int eol,
379     void *userdata)
380 {
381     AudioServerDump *asDump = reinterpret_cast<AudioServerDump *>(userdata);
382     CHECK_AND_RETURN_LOG(asDump != nullptr, "Failed to get source output information");
383     pa_threaded_mainloop *mainLoop = reinterpret_cast<pa_threaded_mainloop *>(asDump->mainLoop);
384     CHECK_AND_RETURN_LOG(eol >= 0, "Failed to get source output information: %{public}s",
385         pa_strerror(pa_context_errno(c)));
386     if (eol) {
387         pa_threaded_mainloop_signal(mainLoop, 0);
388         return;
389     }
390     InputOutputInfo sourceOutputInfo;
391     sourceOutputInfo.sampleSpec = i->sample_spec;
392     sourceOutputInfo.corked = i->corked;
393     if (i->proplist != nullptr) {
394         const char *applicationname = pa_proplist_gets(i->proplist, "application.name");
395         const char *processid = pa_proplist_gets(i->proplist, "application.process.id");
396         const char *user = pa_proplist_gets(i->proplist, "application.process.user");
397         const char *sessionid = pa_proplist_gets(i->proplist, "stream.sessionID");
398         const char *sessionstarttime = pa_proplist_gets(i->proplist, "stream.startTime");
399         const char *privacytype = pa_proplist_gets(i->proplist, "stream.privacyType");
400         if (applicationname != nullptr) {
401             string applicationName(applicationname);
402             (sourceOutputInfo.applicationName).assign(applicationName);
403         }
404         if (processid != nullptr) {
405             string processId(processid);
406             (sourceOutputInfo.processId).assign(processId);
407         }
408         if (user != nullptr) {
409             struct passwd *p;
410             if ((p = getpwnam(user)) != nullptr) {
411                 sourceOutputInfo.userId = uint32_t(p->pw_uid);
412             }
413         }
414         if (sessionid != nullptr) {
415             string sessionId(sessionid);
416             (sourceOutputInfo.sessionId).assign(sessionId);
417         }
418         if (sessionstarttime != nullptr) {
419             string sessionStartTime(sessionstarttime);
420             (sourceOutputInfo.sessionStartTime).assign(sessionStartTime);
421         }
422         if (privacytype != nullptr) {
423             string privacyType(privacytype);
424             (sourceOutputInfo.privacyType).assign(privacyType);
425         }
426     }
427     asDump->streamData_.sourceOutputs.push_back(sourceOutputInfo);
428 }
429 
PlaybackSinkDump(std::string & dumpString)430 void AudioServerDump::PlaybackSinkDump(std::string &dumpString)
431 {
432     AUDIO_INFO_LOG("PlaybackSinkDump enter");
433     char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
434 
435     dumpString += "Playback Streams\n";
436 
437     AppendFormat(dumpString, "- %zu Playback stream (s) available:\n", streamData_.sinkInputs.size());
438 
439     for (auto it = streamData_.sinkInputs.begin(); it != streamData_.sinkInputs.end(); it++) {
440         InputOutputInfo sinkInputInfo = *it;
441 
442         AppendFormat(dumpString, "  Stream %d\n", it - streamData_.sinkInputs.begin() + 1);
443         AppendFormat(dumpString, "  - Stream Id: %s\n", (sinkInputInfo.sessionId).c_str());
444         AppendFormat(dumpString, "  - Application Name: %s\n", ((sinkInputInfo.applicationName).c_str()));
445         AppendFormat(dumpString, "  - Process Id: %s\n", (sinkInputInfo.processId).c_str());
446         AppendFormat(dumpString, "  - User Id: %u\n", sinkInputInfo.userId);
447         AppendFormat(dumpString, "  - stream can be captured: %s\n",
448             sinkInputInfo.privacyType == "0" ? "true" : "false");
449 
450         char *inputSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sinkInputInfo.sampleSpec));
451         AppendFormat(dumpString, "  - Stream Configuration: %s\n", inputSampleSpec);
452         dumpString += "  - Status:";
453         dumpString += (sinkInputInfo.corked) ? "STOPPED/PAUSED" : "RUNNING";
454         AppendFormat(dumpString, "\n  - Stream Start Time: %s\n", (sinkInputInfo.sessionStartTime).c_str());
455         dumpString += "\n";
456     }
457 }
458 
RecordSourceDump(std::string & dumpString)459 void AudioServerDump::RecordSourceDump(std::string &dumpString)
460 {
461     char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
462     dumpString += "Record Streams \n";
463     AppendFormat(dumpString, "- %zu Record stream (s) available:\n", streamData_.sourceOutputs.size());
464 
465     for (auto it = streamData_.sourceOutputs.begin(); it != streamData_.sourceOutputs.end(); it++) {
466         InputOutputInfo sourceOutputInfo = *it;
467         AppendFormat(dumpString, "  Stream %d\n", it - streamData_.sourceOutputs.begin() + 1);
468         AppendFormat(dumpString, "  - Stream Id: %s\n", (sourceOutputInfo.sessionId).c_str());
469         AppendFormat(dumpString, "  - Application Name: %s\n", (sourceOutputInfo.applicationName).c_str());
470         AppendFormat(dumpString, "  - Process Id: %s\n", sourceOutputInfo.processId.c_str());
471         AppendFormat(dumpString, "  - User Id: %u\n", sourceOutputInfo.userId);
472 
473         char *outputSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sourceOutputInfo.sampleSpec));
474         AppendFormat(dumpString, "  - Stream Configuration: %s\n", outputSampleSpec);
475         dumpString += "  - Status:";
476         dumpString += (sourceOutputInfo.corked) ? "STOPPED/PAUSED" : "RUNNING";
477         AppendFormat(dumpString, "\n  - Stream Start Time: %s\n", (sourceOutputInfo.sessionStartTime).c_str());
478         dumpString += "\n";
479     }
480 }
481 
HDFModulesDump(std::string & dumpString)482 void AudioServerDump::HDFModulesDump(std::string &dumpString)
483 {
484     char s[PA_SAMPLE_SPEC_SNPRINT_MAX];
485 
486     dumpString += "\nHDF Input Modules\n";
487     AppendFormat(dumpString, "- %zu HDF Input Modules (s) available:\n", streamData_.sourceDevices.size());
488 
489     for (auto it = streamData_.sourceDevices.begin(); it != streamData_.sourceDevices.end(); it++) {
490         SinkSourceInfo sourceInfo = *it;
491 
492         AppendFormat(dumpString, "  Module %d\n", it - streamData_.sourceDevices.begin() + 1);
493         AppendFormat(dumpString, "  - Module Name: %s\n", (sourceInfo.name).c_str());
494         char *hdfOutSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sourceInfo.sampleSpec));
495         AppendFormat(dumpString, "  - Module Configuration: %s\n\n", hdfOutSampleSpec);
496     }
497 
498     dumpString += "HDF Output Modules\n";
499     AppendFormat(dumpString, "- %zu HDF Output Modules (s) available:\n", streamData_.sinkDevices.size());
500 
501     for (auto it = streamData_.sinkDevices.begin(); it != streamData_.sinkDevices.end(); it++) {
502         SinkSourceInfo sinkInfo = *it;
503         AppendFormat(dumpString, "  Module %d\n", it - streamData_.sinkDevices.begin() + 1);
504         AppendFormat(dumpString, "  - Module Name: %s\n", (sinkInfo.name).c_str());
505         char *hdfInSampleSpec = pa_sample_spec_snprint(s, sizeof(s), &(sinkInfo.sampleSpec));
506         AppendFormat(dumpString, "  - Module Configuration: %s\n\n", hdfInSampleSpec);
507     }
508 }
509 
PolicyHandlerDump(std::string & dumpString)510 void AudioServerDump::PolicyHandlerDump(std::string &dumpString)
511 {
512     AUDIO_INFO_LOG("PolicyHandlerDump");
513     AudioService::GetInstance()->Dump(dumpString);
514 }
515 } // namespace AudioStandard
516 } // namespace OHOS
517