xref: /aosp_15_r20/external/autotest/client/site_tests/logging_CrashServices/logging_CrashServices.py (revision 9c5db1993ded3edbeafc8092d69fe5de2ee02df7)
1# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import os, os.path, logging
6from autotest_lib.client.bin import test, utils
7from autotest_lib.client.common_lib import error
8from autotest_lib.client.common_lib.cros import chrome
9from autotest_lib.client.cros.crash.crash_test import CrashTest
10
11
12# TODO(b/185707445): port this test to Tast.
13class logging_CrashServices(test.test):
14    """Verifies crash collection for system services."""
15    version = 3
16
17    process_list = {
18        '/usr/sbin/cryptohomed' : ['.core', '.dmp', '.meta'],
19        '/usr/bin/metrics_daemon' : ['.core', '.dmp', '.meta'],
20        '/usr/bin/powerd' : ['.core', '.dmp', '.meta', '.log'],
21        # Removing rsyslogd until crbug.com/611786 is fixed.
22        # '/usr/sbin/rsyslogd': ['.core', '.dmp', '.meta'],
23        # Removing tcsd crash with reference to crbug.com/380359
24        # '/usr/sbin/tcsd' : ['.core', '.dmp', '.meta'],
25        '/usr/bin/tlsdated' : ['.core', '.dmp', '.meta'],
26        '/usr/bin/shill' : ['.core', '.dmp', '.meta'],
27        '/usr/sbin/update_engine' : ['.core', '.dmp', '.meta', '.log'],
28        '/usr/sbin/wpa_supplicant' : ['.core', '.dmp', '.meta'],
29        '/sbin/session_manager' : ['.core', '.dmp', '.meta']
30    }
31
32    def _kill_processes(self, name):
33        """Kills the process passed as the parameter
34
35        @param name: Name of the process to be killed.
36
37        @returns: exit status of the kill command.
38
39        """
40        return utils.system("killall -w -s SEGV %s" % name, ignore_status=True)
41
42
43    def _find_crash_files(self, process_name, extension):
44        """Find if the crash dumps with appropriate extensions are created.
45
46        @param process_name: Name of the process killed.
47        @param extension: Extension of the dump files to be created.
48
49        @returns: Returns the name of the dump file.
50
51        """
52        return self._find_file_in_path(CrashTest._SYSTEM_CRASH_DIR,
53                                       process_name, extension)
54
55
56    def _find_file_in_path(self, path, process_name, filetype):
57        """Checks the creation of the the dump files with appropriate extensions.
58           Also check for the file size of the dumps created.
59
60        @param path: Directory path where the dump files are expected.
61        @param process_name: Name of the process.
62        @param filetype: Extension of the dump file.
63
64        @returns: Name of the dump file.
65
66        """
67        try:
68            entries = os.listdir(path)
69        except OSError:
70            return None
71
72        for entry in entries:
73            (filename, ext) = os.path.splitext(entry)
74            if ext == filetype and filename.startswith(process_name):
75                file_path = path + '/' + entry
76                logging.info('the path is %s', file_path)
77                if os.path.getsize(file_path) > 0:
78                    return entry
79        return None
80
81    def _remove_crash_file(self, path, process_name):
82        """Remove crash dumps to prevent unnecessary crash reporting.
83
84        @param path: Directory path where the dump files are expected.
85        @param process_name: Name of the process.
86
87        """
88        try:
89            # sort by name so that we can find latest crash first
90            entries = sorted(os.listdir(path), reverse=True)
91        except OSError:
92            return
93
94        crash_name = None
95        for entry in entries:
96            (filename, _) = os.path.splitext(entry)
97            if filename.startswith(process_name):
98                crash_name = filename
99                break
100        if crash_name is None:
101            return
102
103        for entry in entries:
104            if entry.startswith(crash_name):
105                os.remove(path + '/' + entry)
106
107    def _test_process(self, process_path, crash_extensions):
108        """Calls a function to kill the process and then wait
109           for the creation of the dump files.
110
111        @param process_path: Path of the process to be killed.
112        @param crash_extensions: Extension of the dump file expected.
113
114        """
115        if self._kill_processes(process_path):
116            raise error.TestFail("Failed to kill process %s" % process_path)
117
118        process_name = os.path.basename(process_path)
119
120        for crash_ext in crash_extensions:
121            # wait for appropriate dump files in a crash directory.
122            utils.poll_for_condition(
123                condition=lambda: self._find_crash_files(process_name,
124                                                         crash_ext),
125                desc="Waiting for %s for %s" % (crash_ext, process_path))
126
127        self._remove_crash_file(CrashTest._SYSTEM_CRASH_DIR, process_name)
128        # tlsdated generates two groups of crash files for some unknown reason,
129        # so we need to remove both of them.
130        if process_name == "tlsdated":
131            self._remove_crash_file(CrashTest._SYSTEM_CRASH_DIR, process_name)
132
133    def run_once(self, process_path=None, crash_extensions=None):
134        if process_path:
135            self._test_process(process_path,crash_extensions)
136            return
137
138        with chrome.Chrome():
139            for process_path in self.process_list.keys():
140                self.job.run_test("logging_CrashServices",
141                                  process_path=process_path,
142                                  crash_extensions=self.process_list.get(process_path),
143                                  tag=os.path.basename(process_path))
144