1424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)# found in the LICENSE file. 43551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import glob 53551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import heapq 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import logging 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import subprocess as subprocess 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import shutil 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import sys 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import tempfile 123551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)import time 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import util 15a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends import browser_backend 16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends.chrome import chrome_browser_backend 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 18a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)class DesktopBrowserBackend(chrome_browser_backend.ChromeBrowserBackend): 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """The backend for controlling a locally-executed browser instance, on Linux, 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) Mac or Windows. 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) """ 2258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) def __init__(self, browser_options, executable, flash_path, is_content_shell, 2358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) browser_directory, output_profile_path, extensions_to_load): 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) super(DesktopBrowserBackend, self).__init__( 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) is_content_shell=is_content_shell, 2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) supports_extensions=not is_content_shell, 2758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) browser_options=browser_options, 2858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) output_profile_path=output_profile_path, 2958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) extensions_to_load=extensions_to_load) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Initialize fields so that an explosion during init doesn't break in Close. 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._proc = None 333551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self._tmp_profile_dir = None 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tmp_output_file = None 352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._executable = executable 372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._executable: 382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) raise Exception('Cannot create browser, no executable found!') 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch self._flash_path = flash_path 417dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch if self._flash_path and not os.path.exists(self._flash_path): 427dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch logging.warning(('Could not find flash at %s. Running without flash.\n\n' 437dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 'To fix this see http://go/read-src-internal') % 447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._flash_path) 457dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch self._flash_path = None 46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if len(extensions_to_load) > 0 and is_content_shell: 482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) raise browser_backend.ExtensionsNotSupportedException( 492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 'Content shell does not support extensions.') 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 51bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch self._browser_directory = browser_directory 52f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._port = None 5390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._profile_dir = None 542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._supports_net_benchmarking = True 553551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self._tmp_minidump_dir = tempfile.mkdtemp() 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 57a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) self._SetupProfile() 58a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 59a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) def _SetupProfile(self): 6058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if not self.browser_options.dont_override_profile: 61424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if self._output_profile_path: 62424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) # If both |_output_profile_path| and |profile_dir| are specified then 63424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) # the calling code will throw an exception, so we don't need to worry 64424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) # about that case here. 65424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) self._tmp_profile_dir = self._output_profile_path 66424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) else: 67424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) self._tmp_profile_dir = tempfile.mkdtemp() 6858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) profile_dir = self._profile_dir or self.browser_options.profile_dir 69a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if profile_dir: 70a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) if self.is_content_shell: 71a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) logging.critical('Profiles cannot be used with content shell') 72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) sys.exit(1) 73424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) logging.info("Using profile directory:'%s'." % profile_dir) 743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) shutil.rmtree(self._tmp_profile_dir) 753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) shutil.copytree(profile_dir, self._tmp_profile_dir) 762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 77a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) def _LaunchBrowser(self): 782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args = [self._executable] 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args.extend(self.GetBrowserStartupArgs()) 801e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if self.browser_options.startup_url: 811e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) args.append(self.browser_options.startup_url) 823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) env = os.environ.copy() 833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) env['CHROME_HEADLESS'] = '1' # Don't upload minidumps. 843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) env['BREAKPAD_DUMP_LOCATION'] = self._tmp_minidump_dir 85f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) logging.debug('Starting Chrome %s', args) 8658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if not self.browser_options.show_stdout: 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tmp_output_file = tempfile.NamedTemporaryFile('w', 0) 882a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._proc = subprocess.Popen( 893551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) args, stdout=self._tmp_output_file, stderr=subprocess.STDOUT, env=env) 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 913551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) self._proc = subprocess.Popen(args, env=env) 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) try: 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._WaitForBrowserToComeUp() 952a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._PostBrowserStartupInitialization() 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) except: 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.Close() 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) raise 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def GetBrowserStartupArgs(self): 1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args = super(DesktopBrowserBackend, self).GetBrowserStartupArgs() 102f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._port = util.GetUnreservedAvailableLocalPort() 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args.append('--remote-debugging-port=%i' % self._port) 1043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) args.append('--enable-crash-reporter-for-testing') 1052a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self.is_content_shell: 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args.append('--window-size=1280,1024') 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if self._flash_path: 108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch args.append('--ppapi-flash-path=%s' % self._flash_path) 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if self._supports_net_benchmarking: 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args.append('--enable-net-benchmarking') 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) else: 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) args.append('--enable-benchmarking') 11358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles) if not self.browser_options.dont_override_profile: 1143551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) args.append('--user-data-dir=%s' % self._tmp_profile_dir) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return args 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 11790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) def SetProfileDirectory(self, profile_dir): 11890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) # Make sure _profile_dir hasn't already been set. 11990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) assert self._profile_dir is None 12090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) if self.is_content_shell: 12290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) logging.critical('Profile creation cannot be used with content shell') 12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) sys.exit(1) 12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) self._profile_dir = profile_dir 12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 127a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) def Start(self): 128a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) self._LaunchBrowser() 129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 130a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) # For old chrome versions, might have to relaunch to have the 131a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) # correct net_benchmarking switch. 1323551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if self.chrome_branch_number < 1418: 133a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) self.Close() 134a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) self._supports_net_benchmarking = False 135a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) self._LaunchBrowser() 136a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles) 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) @property 1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def pid(self): 1392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if self._proc: 1402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return self._proc.pid 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return None 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 14390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) @property 144bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch def browser_directory(self): 145bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch return self._browser_directory 146bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch 147bb1529ce867d8845a77ec7cdf3e3003ef1771a40Ben Murdoch @property 14890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) def profile_directory(self): 1493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return self._tmp_profile_dir 15090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) 1512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def IsBrowserRunning(self): 1522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return self._proc.poll() == None 1532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def GetStandardOutput(self): 1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) assert self._tmp_output_file, "Can't get standard output with show_stdout" 1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tmp_output_file.flush() 1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) try: 1582a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) with open(self._tmp_output_file.name) as f: 1592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return f.read() 1602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) except IOError: 1612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return '' 1622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1637dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch def GetStackTrace(self): 1643551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) stackwalk = util.FindSupportBinary('minidump_stackwalk') 1653551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if not stackwalk: 1663551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) logging.warning('minidump_stackwalk binary not found. Must build it to ' 1673551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 'symbolize crash dumps. Returning browser stdout.') 1683551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return self.GetStandardOutput() 1693551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1703551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) dumps = glob.glob(os.path.join(self._tmp_minidump_dir, '*.dmp')) 1713551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if not dumps: 1723551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) logging.warning('No crash dump found. Returning browser stdout.') 1733551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return self.GetStandardOutput() 1743551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) most_recent_dump = heapq.nlargest(1, dumps, os.path.getmtime)[0] 1753551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if os.path.getmtime(most_recent_dump) < (time.time() - (5 * 60)): 176f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) logging.warning('Crash dump is older than 5 minutes. May not be correct.') 177f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 178f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) symbols = glob.glob(os.path.join(self._browser_directory, '*.breakpad*')) 179f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if not symbols: 180f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) logging.warning('No breakpad symbols found. Returning browser stdout.') 181f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return self.GetStandardOutput() 1823551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1833551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) minidump = most_recent_dump + '.stripped' 1843551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) with open(most_recent_dump, 'rb') as infile: 1853551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) with open(minidump, 'wb') as outfile: 1863551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) outfile.write(''.join(infile.read().partition('MDMP')[1:])) 1873551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 1883551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) symbols_path = os.path.join(self._tmp_minidump_dir, 'symbols') 1891e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) for symbol in sorted(symbols, key=os.path.getmtime, reverse=True): 1901e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if not os.path.isfile(symbol): 1911e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) continue 1923551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) with open(symbol, 'r') as f: 1933551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) fields = f.readline().split() 1943551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) if not fields: 1953551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) continue 1963551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) sha = fields[3] 1973551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) binary = ' '.join(fields[4:]) 1983551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) symbol_path = os.path.join(symbols_path, binary, sha) 1991e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) if os.path.exists(symbol_path): 2001e9bf3e0803691d0a228da41fc608347b6db4340Torne (Richard Coles) continue 2013551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) os.makedirs(symbol_path) 2023551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) shutil.copyfile(symbol, os.path.join(symbol_path, binary + '.sym')) 2033551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) 2043551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) error = tempfile.NamedTemporaryFile('w', 0) 2053551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) return subprocess.Popen( 2063551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) [stackwalk, minidump, symbols_path], 2073551c9c881056c480085172ff9840cab31610854Torne (Richard Coles) stdout=subprocess.PIPE, stderr=error).communicate()[0] 2087dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch 2092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def __del__(self): 2102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self.Close() 2112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def Close(self): 2132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) super(DesktopBrowserBackend, self).Close() 2142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if self._proc: 2162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def IsClosed(): 2182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not self._proc: 2192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return True 2202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return self._proc.poll() != None 2212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Try to politely shutdown, first. 223f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) if not IsClosed(): 224f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._proc.terminate() 225f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) try: 226f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) util.WaitFor(IsClosed, timeout=5) 227f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._proc = None 228f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) except util.TimeoutException: 229f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) logging.warning('Failed to gracefully shutdown. Proceeding to kill.') 2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) # Kill it. 2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if not IsClosed(): 2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._proc.kill() 2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) try: 235f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) util.WaitFor(IsClosed, timeout=10) 2362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) except util.TimeoutException: 2372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) raise Exception('Could not shutdown the browser.') 238f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) finally: 239f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) self._proc = None 2402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 241424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if self._output_profile_path: 242424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) # If we need the output then double check that it exists. 243424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if not (self._tmp_profile_dir and os.path.exists(self._tmp_profile_dir)): 244424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) raise Exception("No profile directory generated by Chrome: '%s'." % 245424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) self._tmp_profile_dir) 246424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) else: 247424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) # If we don't need the profile after the run then cleanup. 248424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) if self._tmp_profile_dir and os.path.exists(self._tmp_profile_dir): 249424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) shutil.rmtree(self._tmp_profile_dir, ignore_errors=True) 250424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles) self._tmp_profile_dir = None 2512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if self._tmp_output_file: 2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tmp_output_file.close() 2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) self._tmp_output_file = None 2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 2562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) def CreateForwarder(self, *port_pairs): 257c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return browser_backend.DoNothingForwarder(*port_pairs) 258