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 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.SetTraceFor(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", "iteration-info": (self._iteration_info.AsDict() if self._iteration_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 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 self._OpenLogFile() 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: util.WaitFor(self._IsStarted, 30) 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 exceptions.TimeoutException: 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, 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: util.WaitFor(self._IsStarted, timeout) logging.info('TsProxy port: %s', self._port) self._is_running = True except exceptions.TimeoutException: err = self.StopServer() raise RuntimeError('Error starting tsproxy: %s' % err)
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 __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, device, port_pairs): super(AndroidForwarder, self).__init__(port_pairs) self._device = device forwarder.Forwarder.Map([(p.remote_port, p.local_port) for p in port_pairs if p], self._device) self._port_pairs = forwarders.PortPairs(*[ forwarders. PortPair(p.local_port, forwarder.Forwarder.DevicePortForHostPort(p.local_port) ) if p else None for p in port_pairs ]) atexit_with_log.Register(self.Close)
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.AddEventsTo(trace_data_module.TELEMETRY_PART, data) 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 __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)