def _CreateTraceConfigFile(self, config): assert not self._trace_config_file if self._platform_backend.GetOSName() == 'android': self._trace_config_file = os.path.join( _CHROME_TRACE_CONFIG_DIR_ANDROID, _CHROME_TRACE_CONFIG_FILE_NAME) self._platform_backend.device.WriteFile( self._trace_config_file, self._CreateTraceConfigFileString(config), as_root=True) # The config file has fixed path on Android. We need to ensure it is # always cleaned up. atexit_with_log.Register(self._RemoveTraceConfigFile) elif self._platform_backend.GetOSName() == 'chromeos': self._trace_config_file = os.path.join( _CHROME_TRACE_CONFIG_DIR_CROS, _CHROME_TRACE_CONFIG_FILE_NAME) cri = self._platform_backend.cri cri.PushContents(self._CreateTraceConfigFileString(config), self._trace_config_file) cri.Chown(self._trace_config_file) # The config file has fixed path on CrOS. We need to ensure it is # always cleaned up. atexit_with_log.Register(self._RemoveTraceConfigFile) elif self._platform_backend.GetOSName() in _DESKTOP_OS_NAMES: self._trace_config_file = os.path.join( tempfile.mkdtemp(), _CHROME_TRACE_CONFIG_FILE_NAME) with open(self._trace_config_file, 'w') as f: trace_config_string = self._CreateTraceConfigFileString(config) logging.info('Trace config file string: %s', trace_config_string) f.write(trace_config_string) os.chmod(self._trace_config_file, os.stat(self._trace_config_file).st_mode | stat.S_IROTH) else: raise NotImplementedError
def StartServer(self): """Start Web Page Replay and verify that it started. Returns: A dictionary mapping the keys 'http', 'https', and (if used) 'dns' to the respective ports of the replay server. Raises: ReplayNotStartedError: if Replay start-up fails. """ is_posix = sys.platform.startswith('linux') or sys.platform == 'darwin' logging.info('Starting Web-Page-Replay: %s', self._cmd_line) self._CreateTempLogFilePath() with open(self._temp_log_file_path, 'w') as log_fh: self.replay_process = subprocess.Popen( self._cmd_line, stdout=log_fh, stderr=subprocess.STDOUT, preexec_fn=(_ResetInterruptHandler if is_posix else None)) try: py_utils.WaitFor(self._IsStarted, 30) logging.info('WPR ports: %s' % self._started_ports) atexit_with_log.Register(self.StopServer) return dict(self._started_ports) except Exception: self.StopServer() raise ReplayNotStartedError( 'Web Page Replay failed to start. Log output:\n%s' % ''.join(self._LogLines()))
def _StartMsrServerIfNeeded(self): if self._msr_server_handle: return _InstallWinRing0() pipe_name = r"\\.\pipe\msr_server_pipe_{}".format(os.getpid()) # Try to open a named pipe to receive a msr port number from server process. pipe = win32pipe.CreateNamedPipe( pipe_name, win32pipe.PIPE_ACCESS_INBOUND, win32pipe.PIPE_TYPE_MESSAGE | win32pipe.PIPE_WAIT, 1, 32, 32, 300, None) parameters = ( os.path.join(os.path.dirname(__file__), 'msr_server_win.py'), pipe_name, ) self._msr_server_handle = self.LaunchApplication( sys.executable, parameters, elevate_privilege=True) if pipe != win32file.INVALID_HANDLE_VALUE: if win32pipe.ConnectNamedPipe(pipe, None) == 0: self._msr_server_port = int(win32file.ReadFile(pipe, 32)[1]) win32api.CloseHandle(pipe) # Wait for server to start. try: socket.create_connection(('127.0.0.1', self._msr_server_port), 5).close() except socket.error: self.CloseMsrServer() atexit_with_log.Register(TerminateProcess, self._msr_server_handle)
def StartServer(self): """Start Web Page Replay and verify that it started. Returns: A forwarders.PortSet(http, https, dns) tuple; with dns None if unused. Raises: ReplayNotStartedError: if Replay start-up fails. """ is_posix = sys.platform.startswith('linux') or sys.platform == 'darwin' logging.info('Starting Web-Page-Replay: %s', self._cmd_line) self._CreateTempLogFilePath() with open(self._temp_log_file_path, 'w') as log_fh: self.replay_process = subprocess.Popen( self._cmd_line, stdout=log_fh, stderr=subprocess.STDOUT, preexec_fn=(_ResetInterruptHandler if is_posix else None)) try: py_utils.WaitFor(self._IsStarted, 30) logging.info('WPR ports: %s' % self._started_ports) atexit_with_log.Register(self.StopServer) return forwarders.PortSet( self._started_ports['http'], self._started_ports['https'], self._started_ports.get('dns'), # None if unused ) except py_utils.TimeoutException: raise ReplayNotStartedError( 'Web Page Replay failed to start. Log output:\n%s' % ''.join(self._LogLines()))
def StartServer(self, timeout=10): """Start TsProxy server and verify that it started. """ cmd_line = [sys.executable, _TSPROXY_PATH] cmd_line.extend([ '--port=0' ]) # Use port 0 so tsproxy picks a random available port. if self._host_ip: cmd_line.append('--desthost=%s' % self._host_ip) if self._http_port: cmd_line.append('--mapports=443:%s,*:%s' % (self._https_port, self._http_port)) logging.info('Tsproxy commandline: %r' % cmd_line) self._proc = subprocess.Popen(cmd_line, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1) atexit_with_log.Register(self.StopServer) try: py_utils.WaitFor(self._IsStarted, timeout) logging.info('TsProxy port: %s', self._port) self._is_running = True except py_utils.TimeoutException: err = self.StopServer() raise RuntimeError('Error starting tsproxy: %s' % err)
def StartServer(self, timeout=10, retries=None): """Start TsProxy server and verify that it started.""" del retries # Handled by decorator. cmd_line = [sys.executable, _TSPROXY_PATH] # Use port 0 so tsproxy picks a random available port. cmd_line.extend(['--port=0']) if self._host_ip: cmd_line.append('--desthost=%s' % self._host_ip) if self._http_port: cmd_line.append( '--mapports=443:%s,*:%s' % (self._https_port, self._http_port)) logging.info('Tsproxy commandline: %s', cmd_line) self._proc = subprocess.Popen( cmd_line, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1) self._non_blocking = False if fcntl: logging.info('fcntl is supported, trying to set ' 'non blocking I/O for the ts_proxy process') fd = self._proc.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) self._non_blocking = True atexit_with_log.Register(self.StopServer) try: py_utils.WaitFor(self._IsStarted, timeout) logging.info('TsProxy port: %s', self._port) self._is_running = True except py_utils.TimeoutException: err = self.StopServer() if err: logging.error('Error stopping WPR server:\n%s', err) raise TsProxyServerError( 'Error starting tsproxy: timed out after %s seconds' % timeout)
def StartAgentTracing(self, config, timeout): """Start tracing on the BattOr. Args: config: A TracingConfig instance. timeout: number of seconds that this tracing agent should try to start tracing until timing out. Returns: True if the tracing agent started successfully. """ if not config.enable_battor_trace: return False try: if self._battery: self._battery.SetCharging(False) atexit_with_log.Register(_ReenableChargingIfNeeded, self._battery) self._battor.StartShell() self._battor.StartTracing() return True except battor_error.BattOrError: if self._battery: self._battery.SetCharging(True) raise
def StartServer(self): """Start Web Page Replay and verify that it started. Returns: A dictionary mapping the keys 'http', 'https', and (if used) 'dns' to the respective ports of the replay server. Raises: ReplayNotStartedError: if Replay start-up fails. """ is_posix = sys.platform.startswith('linux') or sys.platform == 'darwin' logging.info('Starting Web-Page-Replay: %s', self._cmd_line) self._CreateTempLogFilePath() with open(self._temp_log_file_path, 'w') as log_fh: self.replay_process = subprocess.Popen( self._cmd_line, stdout=log_fh, stderr=subprocess.STDOUT, preexec_fn=(_ResetInterruptHandler if is_posix else None)) try: # TODO(crbug.com/805418): consider changing this to wait with I/O timeout. # The 120s timeout is based on past failures (e.g: crbug.com/812639). py_utils.WaitFor(self._IsStarted, timeout=120) logging.info('WPR ports: %s' % self._started_ports) atexit_with_log.Register(self.StopServer) return dict(self._started_ports) except Exception: log_output = self.StopServer() raise ReplayNotStartedError( 'Web Page Replay failed to start. Log output:\n%s' % log_output)
def __init__(self, device, local_port, remote_port): super(AndroidForwarder, self).__init__() self._device = device assert local_port, 'Local port must be given' forwarder.Forwarder.Map([(remote_port, local_port)], self._device) remote_port = forwarder.Forwarder.DevicePortForHostPort(local_port) self._StartedForwarding(local_port, remote_port) atexit_with_log.Register(self.Close)
def __init__(self, device, port_pair): super(AndroidForwarder, self).__init__(port_pair) self._device = device forwarder.Forwarder.Map( [(port_pair.remote_port, port_pair.local_port)], self._device) self._port_pair = (forwarders.PortPair( port_pair.local_port, forwarder.Forwarder.DevicePortForHostPort(port_pair.local_port))) atexit_with_log.Register(self.Close)
def __init__(self, target_platform, android_device=None, battor_path=None, battor_map_file=None, battor_map=None, serial_log_bucket=None, autoflash=True): """Constructor. Args: target_platform: Platform BattOr is attached to. android_device: Serial number of Android device. battor_path: Path to BattOr device. battor_map_file: File giving map of [device serial: BattOr path] battor_map: Map of [device serial: BattOr path] serial_log_bucket: The cloud storage bucket to which BattOr agent serial logs are uploaded on failure. Attributes: _battor_path: Path to BattOr. Typically similar to /tty/USB0. _battor_agent_binary: Path to the BattOr agent binary used to communicate with the BattOr. _tracing: A bool saying if tracing has been started. _battor_shell: A subprocess running the battor_agent_binary _trace_results_path: Path to BattOr trace results file. _serial_log_bucket: Cloud storage bucket to which BattOr agent serial logs are uploaded on failure. _serial_log_file: Temp file for the BattOr agent serial log. """ self._battor_path = self._GetBattOrPath(target_platform, android_device, battor_path, battor_map_file, battor_map) config = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'battor_binary_dependencies.json') self._dm = dependency_manager.DependencyManager( [dependency_manager.BaseConfig(config)]) self._battor_agent_binary = self._dm.FetchPath( 'battor_agent_binary', '%s_%s' % (sys.platform, platform.machine())) self._autoflash = autoflash self._serial_log_bucket = serial_log_bucket self._tracing = False self._battor_shell = None self._trace_results_path = None self._start_tracing_time = None self._stop_tracing_time = None self._trace_results = None self._serial_log_file = None self._target_platform = target_platform self._git_hash = None atexit_with_log.Register(self.KillBattOrShell)
def _CreateTraceConfigFile(self, config): assert not self._trace_config_file os_name = self._platform_backend.GetOSName() if os_name == 'android': self._trace_config_file = os.path.join( _CHROME_TRACE_CONFIG_DIR_ANDROID, _CHROME_TRACE_CONFIG_FILE_NAME) self._platform_backend.device.WriteFile( self._trace_config_file, self._CreateTraceConfigFileString(config), as_root=True) # The config file has fixed path on Android. We need to ensure it is # always cleaned up. atexit_with_log.Register(self._RemoveTraceConfigFile) elif os_name == 'chromeos': self._trace_config_file = os.path.join( _CHROME_TRACE_CONFIG_DIR_CROS, _CHROME_TRACE_CONFIG_FILE_NAME) cri = self._platform_backend.cri # Before push the config file to DUT, first make sure the DUT is not # write-protected, and remount the root here to avoid losing the config # file. cri.MakeRootReadWriteIfNecessary() cri.PushContents(self._CreateTraceConfigFileString(config), self._trace_config_file) cri.Chown(self._trace_config_file) # The config file has fixed path on CrOS. We need to ensure it is # always cleaned up. atexit_with_log.Register(self._RemoveTraceConfigFile) elif os_name in _DESKTOP_OS_NAMES: self._trace_config_file = os.path.join( tempfile.mkdtemp(), _CHROME_TRACE_CONFIG_FILE_NAME) with open(self._trace_config_file, 'w') as f: trace_config_string = self._CreateTraceConfigFileString(config) logging.info('Trace config file string: %s', trace_config_string) f.write(trace_config_string) os.chmod(self._trace_config_file, os.stat(self._trace_config_file).st_mode | stat.S_IROTH) else: raise NotImplementedError('Tracing not supported on: %s' % os_name)
def CollectAgentTraceData(self, trace_data_builder): if not self._is_tracing_controllable: return assert not trace_event.trace_is_enabled( ), 'Stop tracing before collection.' with open(self._trace_log, 'r') as fp: data = ast.literal_eval(fp.read() + ']') trace_data_builder.AddTraceFor( trace_data_module.TELEMETRY_PART, { "traceEvents": data, "metadata": { # TODO(charliea): For right now, we use "TELEMETRY" as the clock # domain to guarantee that Telemetry is given its own clock # domain. Telemetry isn't really a clock domain, though: it's a # system that USES a clock domain like LINUX_CLOCK_MONOTONIC or # WIN_QPC. However, there's a chance that a Telemetry controller # running on Linux (using LINUX_CLOCK_MONOTONIC) is interacting # with an Android phone (also using LINUX_CLOCK_MONOTONIC, but # on a different machine). The current logic collapses clock # domains based solely on the clock domain string, but we really # should to collapse based on some (device ID, clock domain ID) # tuple. Giving Telemetry its own clock domain is a work-around # for this. "clock-domain": "TELEMETRY", "telemetry": (self._telemetry_info.AsDict() if self._telemetry_info else {}), } }) try: os.remove(self._trace_log) self._trace_log = None except OSError: logging.exception( 'Error when deleting %s, will try again at exit.', self._trace_log) def DeleteAtExit(path): os.remove(path) atexit_with_log.Register(DeleteAtExit, self._trace_log) self._trace_log = None
def EnableListingStrayProcessesUponExitHook(): def _ListAllSubprocesses(): try: import psutil except ImportError: logging.warning( 'psutil is not installed on the system. Not listing possible ' 'leaked processes. To install psutil, see: ' 'https://pypi.python.org/pypi/psutil') return telemetry_pid = os.getpid() parent = psutil.Process(telemetry_pid) if hasattr(parent, 'children'): children = parent.children(recursive=True) else: # Some old version of psutil use get_children instead children. children = parent.get_children() if children: leak_processes_info = [] for p in children: if inspect.ismethod(p.name): name = p.name() else: # Process.name is a property in old versions of psutil. name = p.name process_info = '%s (%s)' % (name, p.pid) try: if inspect.ismethod(p.cmdline): cmdline = p.cmdline() else: cmdline = p.cmdline process_info += ' - %s' % cmdline except Exception as e: # pylint: disable=broad-except logging.warning(str(e)) leak_processes_info.append(process_info) logging.warning('Telemetry leaks these processes: %s', ', '.join(leak_processes_info)) atexit_with_log.Register(_ListAllSubprocesses)
def StartServer(self, timeout=10): """Start TsProxy server and verify that it started. """ cmd_line = [sys.executable, _TSPROXY_PATH] cmd_line.extend([ '--port=0' ]) # Use port 0 so tsproxy picks a random available port. if self._host_ip: cmd_line.append('--desthost=%s' % self._host_ip) if self._http_port: cmd_line.append('--mapports=443:%s,*:%s' % (self._https_port, self._http_port)) logging.info('Tsproxy commandline: %r' % cmd_line) self._proc = subprocess.Popen(cmd_line, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=1) self._non_blocking = False if fcntl: logging.info('fcntl is supported, try setting ' 'non blocking I/O for the ts_proxy process') fd = self._proc.stdout.fileno() fl = fcntl.fcntl(fd, fcntl.F_GETFL) fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK) self._non_blocking = True atexit_with_log.Register(self.StopServer) try: py_utils.WaitFor(self._IsStarted, timeout) logging.info('TsProxy port: %s', self._port) self._is_running = True except py_utils.TimeoutException: # TODO(nedn): remove this debug log once crbug.com/766877 is resolved ps_util.ListAllSubprocesses() err = self.StopServer() raise RuntimeError('Error starting tsproxy: %s' % err)
def __init__(self, power_monitors, battery): super(AndroidPowerMonitorController, self).__init__() self._candidate_power_monitors = power_monitors self._active_monitors = [] self._battery = battery atexit_with_log.Register(_ReenableChargingIfNeeded, self._battery)
def EnableListingStrayProcessesUponExitHook(): atexit_with_log.Register(ListAllSubprocesses)