xref: /aosp_15_r20/external/autotest/client/site_tests/audio_CrasCheck/audio_CrasCheck.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Lint as: python2, python3
2# Copyright 2015 The Chromium OS Authors. All rights reserved.
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
5
6import logging
7import os
8import time
9
10from autotest_lib.client.bin import test
11from autotest_lib.client.bin import utils
12from autotest_lib.client.common_lib.cros import chrome
13from autotest_lib.client.common_lib import error
14from autotest_lib.client.cros.audio import cras_utils
15
16_CRASH_PATH = '/var/spool/crash'
17_JS = """
18var c = new AudioContext();
19var o = c.createOscillator();
20o.connect(c.destination); o.start();
21"""
22
23
24class audio_CrasCheck(test.test):
25    """Verifies cras using its status, active streams and crashes"""
26
27    version = 1
28    _check = {
29            'crashes_on_boot': False,
30            'stream_activation': False,
31            'cras_status': False,
32            'crashes_at_end': False
33    }
34
35    def run_once(self):
36        # Check for existing cras crashes which might occur during UI bring up.
37        # TODO: (rohitbm) check if we need to reboot the DUT before the test
38        #       start to verify cras crashes during boot.
39        existing_crash_reports = self.collect_cras_crash()
40        if len(existing_crash_reports) == 0:
41            self._check['crashes_on_boot'] = True
42
43        # Capturing cras pid before startig the test.
44        cras_pid_1 = utils.get_oldest_pid_by_name('/usr/bin/cras')
45
46        with chrome.Chrome(init_network_controller=True) as self._cr:
47            # Push the 1st stream
48            self.push_new_stream(self._cr.browser.tabs.New())
49
50            # Capturing cras pid before opening a new set of audio streams.
51            cras_pid_2 = utils.get_oldest_pid_by_name('/usr/bin/cras')
52
53            # Push the 2nd stream
54            self.push_new_stream(self._cr.browser.tabs.New())
55
56            # Let's play audio for sometime to ensure that
57            # long playback is good.
58            time.sleep(10)
59
60            total_tests = 2
61            active_streams = cras_utils.get_active_stream_count()
62            logging.debug(
63                    'Number of active streams after opening all tabs: %d.',
64                    active_streams)
65            if active_streams >= total_tests:
66                self._check['stream_activation'] = True
67
68            # Capturing cras pid after opening all audio/video streams.
69            cras_pid_3 = utils.get_oldest_pid_by_name('/usr/bin/cras')
70
71            # Close all open audio streams.
72            while total_tests > 0:
73                self._cr.browser.tabs[total_tests].Close()
74                total_tests -= 1
75                time.sleep(1)
76            active_streams = cras_utils.get_active_stream_count()
77            logging.debug(
78                    'Number of active streams after closing all tabs: %d.',
79                    active_streams)
80
81            # Capturing cras pid after closing all audio/stream streams.
82            cras_pid_4 = utils.get_oldest_pid_by_name('/usr/bin/cras')
83
84            if cras_pid_1 == cras_pid_2 == cras_pid_3 == cras_pid_4:
85                self._check['cras_status'] = True
86
87        new_crash_reports = self.collect_cras_crash()
88        new_reports = list(
89                set(new_crash_reports) - set(existing_crash_reports))
90        if len(new_reports) == 0:
91            self._check['crashes_at_end'] = True
92
93        err_msg = ''
94        if list(self._check.values()).count(False) > 0:
95            if not self._check['crashes_on_boot']:
96                err_msg = ('1. Found cras crashes on boot: %s.\n' %
97                           existing_crash_reports)
98            if not self._check['stream_activation']:
99                err_msg += ('2. CRAS stream count is not matching with '
100                            'number of streams.\n')
101            if not self._check['cras_status']:
102                err_msg += ('CRAS PID changed during the test. CRAS might be '
103                            'crashing while adding/removing streams.\n')
104            if not self._check['crashes_at_end']:
105                err_msg += ('Found cras crashes at the end of the test : %s.' %
106                            new_reports)
107            raise error.TestError(err_msg)
108
109    def push_new_stream(self, tab):
110        """Starts next audio stream from self._streams list.
111
112        @param tab: tab to open an audio stream.
113        """
114        tab.Activate()
115        tab.Navigate("file:///")
116        tab.ExecuteJavaScript(_JS)
117        time.sleep(1)  # Adding a delay so cras can update the active count.
118
119    def collect_cras_crash(self):
120        """Check for cras crashes.
121
122        @return a list of cras crash reports found.
123        """
124
125        crash_reports = []
126        if not os.path.isdir(_CRASH_PATH):
127            logging.debug('No cras crash detected!')
128        else:
129            cras_reports = os.listdir(_CRASH_PATH)
130            crash_reports = [
131                    report for report in cras_reports
132                    if report.startswith('cras')
133            ]
134        return crash_reports
135