• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 The Chromium Authors
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5from __future__ import annotations
6
7from typing import TYPE_CHECKING, Iterable, Optional, Tuple, cast
8
9from crossbench.plt.android_adb import AndroidAdbPlatform
10from crossbench.probes.probe import (Probe, ProbeConfigParser, ProbeContext,
11                                     ProbeIncompatibleBrowser)
12from crossbench.probes.result_location import ResultLocation
13from crossbench.probes.results import LocalProbeResult, ProbeResult
14
15if TYPE_CHECKING:
16  from crossbench.browsers.browser import Browser
17  from crossbench.env import HostEnvironment
18  from crossbench.runner.run import Run
19
20
21class AndroidLogcatProbe(Probe):
22  """
23  Android-only probe to collect logcat traces.
24  """
25  NAME = "logcat"
26  RESULT_LOCATION = ResultLocation.LOCAL
27
28  IS_GENERAL_PURPOSE = True
29
30  @classmethod
31  def config_parser(cls) -> ProbeConfigParser:
32    parser = super().config_parser()
33    parser.add_argument(
34        "filterspec",
35        type=str,
36        is_list=True,
37        default=tuple(),
38        help="Filter specifications are a series of <tag>[:priority]")
39    return parser
40
41  def __init__(self, filterspec: Iterable[str]):
42    super().__init__()
43    self._filterspec = tuple(filterspec)
44
45  @property
46  def filterspec(self) -> Tuple[str, ...]:
47    return self._filterspec
48
49  def validate_browser(self, env: HostEnvironment, browser: Browser) -> None:
50    super().validate_browser(env, browser)
51    if not browser.platform.is_android:
52      raise ProbeIncompatibleBrowser(self, browser, "Only supported on android")
53
54  def get_context(self, run: Run) -> AndroidLogcatProbeContext:
55    return AndroidLogcatProbeContext(self, run)
56
57
58class AndroidLogcatProbeContext(ProbeContext[AndroidLogcatProbe]):
59
60  def __init__(self, probe: AndroidLogcatProbe, run: Run) -> None:
61    super().__init__(probe, run)
62    self._logcat_start_time: Optional[str] = None
63
64  def _get_browser_platform_time(self) -> str:
65    return self.browser_platform.sh_stdout("date",
66                                           "+%Y-%m-%d %H:%M:%S").rstrip()
67
68  def _log_to_logcat(self, msg: str):
69    self.browser_platform.sh("log", "-t", "crossbench", msg)
70
71  @property
72  def browser_platform(self) -> AndroidAdbPlatform:
73    browser_platform = super().browser_platform
74    assert isinstance(browser_platform, AndroidAdbPlatform)
75    return cast(AndroidAdbPlatform, browser_platform)
76
77  def start(self) -> None:
78    self._logcat_start_time = self._get_browser_platform_time()
79    self._log_to_logcat("logcat probe start")
80
81  def stop(self) -> None:
82    self._log_to_logcat("logcat probe end")
83
84  def teardown(self) -> ProbeResult:
85    assert self._logcat_start_time
86    file = self.local_result_path.with_suffix(".txt")
87    with file.open("w", encoding="utf-8") as f:
88      self.host_platform.sh(
89          "adb",
90          "logcat",
91          "-t",
92          self._logcat_start_time + ".000",
93          *self.probe.filterspec,
94          stdout=f)
95
96    return LocalProbeResult(trace=(file,))
97