def _StoreLogcatAsArtifact(self, suffix):
    logcat = self.platform_backend.GetLogCat()
    artifact_name = posixpath.join(
        self.DEBUG_ARTIFACT_PREFIX, 'logcat-%s.txt' % suffix)
    artifact_logger.CreateArtifact(artifact_name, logcat)

    symbolized_logcat = self.platform_backend.SymbolizeLogCat(logcat)
    if symbolized_logcat is None:
      symbolized_logcat = 'Failed to symbolize logcat. Is the script available?'
    artifact_name = posixpath.join(
        self.DEBUG_ARTIFACT_PREFIX, 'symbolized_logcat-%s.txt' % suffix)
    artifact_logger.CreateArtifact(artifact_name, symbolized_logcat)
Example #2
0
    def LogSymbolizedUnsymbolizedMinidumps(self, log_level):
        """Attempts to symbolize all currently unsymbolized minidumps and log them.

    Platforms may override this to provide other crash information in addition
    to the symbolized minidumps.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
    """
        paths = self.GetAllUnsymbolizedMinidumpPaths()
        if not paths:
            logging.log(log_level, 'No unsymbolized minidump paths')
            return
        logging.log(log_level, 'Unsymbolized minidump paths: ' + str(paths))
        for unsymbolized_path in paths:
            sym = self.SymbolizeMinidump(unsymbolized_path)
            # Store the symbolization attempt as an artifact.
            minidump_name = os.path.basename(unsymbolized_path)
            artifact_name = posixpath.join('symbolize_attempts', minidump_name)
            logging.log(log_level,
                        'Saving symbolization attempt as artifact %s',
                        artifact_name)
            artifact_logger.CreateArtifact(artifact_name, sym[1])
            if sym[0]:
                logging.log(log_level, 'Symbolized minidump:\n%s', sym[1])
            else:
                logging.log(log_level, 'Minidump symbolization failed:%s\n',
                            sym[1])
Example #3
0
    def _SymbolizeAndLogMinidumps(self, log_level):
        """Helper function to handle the minidump portion of CollectDebugData.

    Attempts to find all unsymbolized minidumps, symbolize them, save the
    results as artifacts, and log the results.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
    """
        paths = self.GetAllUnsymbolizedMinidumpPaths()
        if not paths:
            logging.log(log_level, 'No unsymbolized minidump paths')
            return
        logging.log(log_level, 'Unsymbolized minidump paths: ' + str(paths))
        for unsymbolized_path in paths:
            valid, output = self.SymbolizeMinidump(unsymbolized_path)
            # Store the symbolization attempt as an artifact.
            minidump_name = os.path.basename(unsymbolized_path)
            artifact_name = posixpath.join('symbolize_attempts', minidump_name)
            logging.log(log_level,
                        'Saving symbolization attempt as artifact %s',
                        artifact_name)
            artifact_logger.CreateArtifact(artifact_name, output)
            if valid:
                logging.log(log_level, 'Symbolized minidump:\n%s', output)
            else:
                logging.log(
                    log_level,
                    'Minidump symbolization failed, check artifact %s for output',
                    artifact_name)
Example #4
0
  def _CollectBrowserLogs(self, log_level):
    """Helper function to handle the browser log part of CollectDebugData.

    Attempts to retrieve the current and previous browser logs, merge them, and
    save the result as an artifact.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
    """
    # /var/log/chrome/chrome is the log for the current browser, but in case
    # there's something useful in the previous browser's logs, merge chrome
    # and chrome.PREVIOUS.
    try:
      current_log = self._cri.GetFileContents('/var/log/chrome/chrome')
    except OSError:
      logging.log(log_level, 'Unexpectedly did not find browser log')
      return
    current_log = '#### Current Chrome Log ####\n\n%s' % current_log
    try:
      previous_log = self._cri.GetFileContents(
          '/var/log/chrome/chrome.PREVIOUS')
    except OSError:
      # This is expected if this is the first browser launch on this device.
      previous_log = 'Did not find a previous Chrome log.'
    merged_log = '%s\n\n#### Previous Chrome Log ####\n\n%s' % (current_log,
                                                                previous_log)
    artifact_name = posixpath.join(
        'browser_logs', 'browser_log-%s' % artifact_logger.GetTimestampSuffix())
    logging.log(log_level, 'Saving browser log as artifact %s', artifact_name)
    artifact_logger.CreateArtifact(artifact_name, merged_log)
Example #5
0
    def _CollectScreenshot(self, log_level, suffix, start_time=None):
        """Helper function to handle the screenshot portion of CollectDebugData.

    Attempts to take a screenshot at the OS level and save it as an artifact.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
      suffix: The suffix to prepend to the names of any created artifacts.
      start_time: If set, prepend elaped time to screenshot path.
          Should be time at which the test started, as a datetime.
          This is done here because it may take a nonzero amount of time
          to take a screenshot.
    """
        screenshot_handle = screenshot.TryCaptureScreenShot(
            self.browser.platform, timeout=self.screenshot_timeout)
        if screenshot_handle:
            with open(screenshot_handle.GetAbsPath(), 'rb') as infile:
                if start_time:
                    # Prepend time since test started to path
                    test_time = datetime.now() - start_time
                    suffix = str(test_time.total_seconds()).replace(
                        '.', '_') + '-' + suffix

                artifact_name = posixpath.join('debug_screenshots',
                                               'screenshot-%s' % suffix)
                logging.log(log_level, 'Saving screenshot as artifact %s',
                            artifact_name)
                artifact_logger.CreateArtifact(artifact_name, infile.read())
        else:
            logging.log(log_level, 'Failed to capture screenshot')
 def _StoreTombstonesAsArtifact(self, suffix):
   tombstones = self.platform_backend.GetTombstones()
   if tombstones is None:
     tombstones = 'Failed to get tombstones. Is the script available?'
   artifact_name = posixpath.join(
       self.DEBUG_ARTIFACT_PREFIX, 'tombstones-%s.txt' % suffix)
   artifact_logger.CreateArtifact(artifact_name, tombstones)
Example #7
0
    def _SymbolizeAndLogMinidumps(self, log_level, data):
        """Helper function to handle the minidump portion of CollectDebugData.

    Attempts to find all unsymbolized minidumps, symbolize them, save the
    results as artifacts, add them to the given DebugData object, and log the
    results.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
      data: The debug_data.DebugData object to add collected data to.
    """
        paths = self.GetAllUnsymbolizedMinidumpPaths()
        # It's probable that CollectDebugData() is being called in response to a
        # crash. Minidumps are usually written to disk in time, but there's no
        # guarantee that is the case. So, if we don't find any minidumps, poll for
        # a bit to ensure we don't miss them.
        if not paths:
            self.browser.GetRecentMinidumpPathWithTimeout(5)
            paths = self.GetAllUnsymbolizedMinidumpPaths()
        if not paths:
            logging.log(log_level, 'No unsymbolized minidump paths')
            return
        logging.log(log_level, 'Unsymbolized minidump paths: ' + str(paths))
        for unsymbolized_path in paths:
            minidump_name = os.path.basename(unsymbolized_path)
            artifact_name = posixpath.join('unsymbolized_minidumps',
                                           minidump_name)
            logging.log(log_level, 'Saving minidump as artifact %s',
                        artifact_name)
            with open(unsymbolized_path, 'rb') as infile:
                artifact_logger.CreateArtifact(artifact_name, infile.read())
            valid, output = self.SymbolizeMinidump(unsymbolized_path)
            # Store the symbolization attempt as an artifact.
            artifact_name = posixpath.join('symbolize_attempts', minidump_name)
            logging.log(log_level,
                        'Saving symbolization attempt as artifact %s',
                        artifact_name)
            artifact_logger.CreateArtifact(artifact_name, output)
            if valid:
                logging.log(log_level, 'Symbolized minidump:\n%s', output)
                data.symbolized_minidumps.append(output)
            else:
                logging.log(
                    log_level,
                    'Minidump symbolization failed, check artifact %s for output',
                    artifact_name)
Example #8
0
 def _StoreUiDumpAsArtifact(self, suffix):
     try:
         ui_dump = self.platform_backend.GetSystemUi().ScreenDump()
         artifact_name = posixpath.join(self.DEBUG_ARTIFACT_PREFIX,
                                        'ui_dump-%s.txt' % suffix)
         artifact_logger.CreateArtifact(artifact_name, '\n'.join(ui_dump))
     except Exception:  # pylint: disable=broad-except
         logging.exception('Failed to store UI dump')
    def _ExtractLibraryNamesFromDump(self, minidump):
        """Extracts library names that may contain symbols from the minidump.

    This is a duplicate of the logic in Chromium's
    //build/android/stacktrace/crashpad_stackwalker.py.

    Returns:
      A list of strings containing library names of interest for symbols.
    """
        default_library_name = 'libmonochrome.so'
        dumper_path = os.path.join(self._build_dir, 'minidump_dump')
        if not os.access(dumper_path, os.X_OK):
            logging.warning(
                'Cannot extract library name from dump because %s is not found, '
                'default to: %s', dumper_path, default_library_name)
            return [default_library_name]

        stdout = None
        try:
            stdout = subprocess.check_output([dumper_path, minidump],
                                             stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            stdout = e.output
            # Dumper errors often do not affect stack walkability, just a warning.
            # It's possible for the same stack to be symbolized multiple times, so
            # add a timestamp suffix to prevent artifact collisions.
            now = datetime.datetime.now()
            suffix = now.strftime('%Y-%m-%d-%H-%M-%S')
            artifact_name = 'dumper_errors/%s-%s' % (
                os.path.basename(minidump), suffix)
            logging.warning(
                'Reading minidump failed, but likely not actually an issue. Saving '
                'output to artifact %s', artifact_name)
            artifact_logger.CreateArtifact(artifact_name, stdout)

        library_names = []
        module_library_line_re = re.compile(
            r'[(]code_file[)]\s+= '
            r'"(?P<library_name>lib[^. ]+.so)"')
        in_module = False
        for line in stdout.splitlines():
            line = line.lstrip().rstrip('\n')
            if line == 'MDRawModule':
                in_module = True
                continue
            if line == '':
                in_module = False
                continue
            if in_module:
                m = module_library_line_re.match(line)
                if m:
                    library_names.append(m.group('library_name'))
        if not library_names:
            logging.warning(
                'Could not find any library name in the dump, '
                'default to: %s', default_library_name)
            return [default_library_name]
        return library_names
Example #10
0
    def _GetMinidumpDumpOutput(self, minidump):
        """Runs minidump_dump on the given minidump.

    Caches the result for re-use.

    Args:
      minidump: The path to the minidump being analyzed.

    Returns:
      A string containing the output of minidump_dump, or None if it could not
      be retrieved for some reason.
    """
        if minidump in self._minidump_dump_output:
            logging.debug('Returning cached minidump_dump output for %s',
                          minidump)
            return self._minidump_dump_output[minidump]

        dumper_path = local_first_binary_manager.GetInstance().FetchPath(
            'minidump_dump')
        if not os.access(dumper_path, os.X_OK):
            logging.warning(
                'Cannot run minidump_dump because %s is not found.',
                dumper_path)
            return None

        # Using subprocess.check_output with stdout/stderr mixed can result in
        # errors due to log messages showing up in the minidump_dump output. So,
        # use Popen and combine into a single string afterwards.
        p = subprocess.Popen([dumper_path, minidump],
                             stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE)
        stdout, stderr = p.communicate()
        stdout = stdout + '\n' + stderr

        if p.returncode != 0:
            # Dumper errors often do not affect stack walkability, just a warning.
            # It's possible for the same stack to be symbolized multiple times, so
            # add a timestamp suffix to prevent artifact collisions.
            now = datetime.datetime.now()
            suffix = now.strftime('%Y-%m-%d-%H-%M-%S')
            artifact_name = 'dumper_errors/%s-%s' % (
                os.path.basename(minidump), suffix)
            logging.warning(
                'Reading minidump failed, but likely not actually an issue. Saving '
                'output to artifact %s', artifact_name)
            artifact_logger.CreateArtifact(artifact_name, stdout)
        if stdout:
            self._minidump_dump_output[minidump] = stdout
        return stdout
    def _GetMinidumpDumpOutput(self, minidump):
        """Runs minidump_dump on the given minidump.

    Caches the result for re-use.

    Args:
      minidump: The path to the minidump being analyzed.

    Returns:
      A string containing the output of minidump_dump, or None if it could not
      be retrieved for some reason.
    """
        if minidump in self._minidump_dump_output:
            logging.debug('Returning cached minidump_dump output for %s',
                          minidump)
            return self._minidump_dump_output[minidump]

        dumper_path = os.path.join(self._build_dir, 'minidump_dump')
        if not os.access(dumper_path, os.X_OK):
            logging.warning(
                'Cannot run minidump_dump because %s is not found.',
                dumper_path)
            return None

        stdout = None
        try:
            stdout = subprocess.check_output([dumper_path, minidump],
                                             stderr=subprocess.STDOUT)
        except subprocess.CalledProcessError as e:
            stdout = e.output
            # Dumper errors often do not affect stack walkability, just a warning.
            # It's possible for the same stack to be symbolized multiple times, so
            # add a timestamp suffix to prevent artifact collisions.
            now = datetime.datetime.now()
            suffix = now.strftime('%Y-%m-%d-%H-%M-%S')
            artifact_name = 'dumper_errors/%s-%s' % (
                os.path.basename(minidump), suffix)
            logging.warning(
                'Reading minidump failed, but likely not actually an issue. Saving '
                'output to artifact %s', artifact_name)
            artifact_logger.CreateArtifact(artifact_name, stdout)
        if stdout:
            self._minidump_dump_output[minidump] = stdout
        return stdout
Example #12
0
    def _CollectStdout(self, log_level, suffix, data):
        """Helper function to handle the stdout part of CollectDebugData.

    Attempts to retrieve stdout, save it as an artifact, and add it to the given
    DebugData object.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
      suffix: The suffix to append to the names of any created artifacts.
      data: The debug_data.DebugData object to add collected data to.
    """
        stdout = self.browser.GetStandardOutput()
        if stdout is None:
            logging.log(log_level, 'Browser did not provide stdout')
            return
        artifact_name = posixpath.join('stdout', 'stdout-%s' % suffix)
        logging.log(log_level, 'Saving stdout as artifact %s', artifact_name)
        artifact_logger.CreateArtifact(artifact_name, stdout)
        data.stdout = stdout
Example #13
0
  def _CollectSystemLog(self, log_level, suffix, data):
    """Helper function to handle the system log part of CollectDebugData.

    Attempts to retrieve the system log, save it as an artifact, and add it to
    the given DebugData object.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
      suffix: The suffix to append to the names of any created artifacts.
      data: The debug_data.DebugData object to add collected data to.
    """
    system_log = self.browser.platform.GetSystemLog()
    if system_log is None:
      logging.log(log_level, 'Platform did not provide a system log')
      return
    artifact_name = posixpath.join('system_logs', 'system_log-%s' % suffix)
    logging.log(log_level, 'Saving system log as artifact %s', artifact_name)
    artifact_logger.CreateArtifact(artifact_name, system_log)
    data.system_log = system_log
Example #14
0
  def _CollectUiLogs(self, log_level):
    """Helper function to handle the UI log part of CollectDebugData.

    Attempts to retrieve the current UI log and save it as an artifact.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
    """
    # Unlike the browser logs, there is no .PREVIOUS version, so we can only
    # easily get the most recent UI log.
    try:
      ui_log = self._cri.GetFileContents('/var/log/ui/ui.LATEST')
    except OSError:
      logging.log(log_level, 'Unexpectedly did not find UI log')
      return
    artifact_name = posixpath.join(
        'ui_logs', 'ui_log-%s' % artifact_logger.GetTimestampSuffix())
    logging.log(log_level, 'Saving UI log as artifact %s', artifact_name)
    artifact_logger.CreateArtifact(artifact_name, ui_log)
Example #15
0
  def _CollectScreenshot(self, log_level, suffix):
    """Helper function to handle the screenshot portion of CollectDebugData.

    Attempts to take a screenshot at the OS level and save it as an artifact.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
      suffix: The suffix to append to the names of any created artifacts.
    """
    screenshot_handle = screenshot.TryCaptureScreenShot(self.browser.platform)
    if screenshot_handle:
      with open(screenshot_handle.GetAbsPath(), 'rb') as infile:
        artifact_name = posixpath.join(
            'debug_screenshots', 'screenshot-%s' % suffix)
        logging.log(
            log_level, 'Saving screenshot as artifact %s', artifact_name)
        artifact_logger.CreateArtifact(artifact_name, infile.read())
    else:
      logging.log(log_level, 'Failed to capture screenshot')
Example #16
0
    def _CollectScreenshot(self, log_level):
        """Helper function to handle the screenshot portion of CollectDebugData.

    Attempts to take a screenshot at the OS level and save it as an artifact.

    Args:
      log_level: The logging level to use from the logging module, e.g.
          logging.ERROR.
    """
        screenshot_handle = screenshot.TryCaptureScreenShot(
            self.browser.platform)
        if screenshot_handle:
            with open(screenshot_handle.GetAbsPath(), 'rb') as infile:
                now = datetime.datetime.now()
                suffix = now.strftime('%Y-%m-%d-%H-%M-%S')
                artifact_name = posixpath.join('debug_screenshots',
                                               'screenshot-' + suffix)
                logging.log(log_level, 'Saving screenshot as artifact %s',
                            artifact_name)
                artifact_logger.CreateArtifact(artifact_name, infile.read())
        else:
            logging.log(log_level, 'Failed to capture screenshot')
 def _StoreUiDumpAsArtifact(self, suffix):
   ui_dump = self.platform_backend.GetSystemUi().ScreenDump()
   artifact_name = posixpath.join(
       self.DEBUG_ARTIFACT_PREFIX, 'ui_dump-%s.txt' % suffix)
   artifact_logger.CreateArtifact(artifact_name, '\n'.join(ui_dump))