146d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)# Copyright 2012 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.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import os
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry import decorators
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import browser_credentials
9f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)from telemetry.core import exceptions
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import extension_dict
115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import local_server
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)from telemetry.core import memory_cache_http_server
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import tab_list
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import wpr_modes
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)from telemetry.core import wpr_server
16a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)from telemetry.core.backends import browser_backend
172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
186e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)
192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)class Browser(object):
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """A running browser instance that can be controlled in a limited way.
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  To create a browser instance, use browser_finder.FindBrowser.
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Be sure to clean up after yourself by calling Close() when you are done with
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  the browser. Or better yet:
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    browser_to_create = FindBrowser(options)
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    with browser_to_create.Create() as browser:
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      ... do all your operations on browser here
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  """
301320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def __init__(self, backend, platform_backend, archive_path,
311320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               append_to_existing_wpr, make_javascript_deterministic,
321320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci               credentials_path):
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    assert platform_backend.platform != None
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._browser_backend = backend
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self._platform_backend = platform_backend
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._wpr_server = None
385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._local_server_controller = local_server.LocalServerController(backend)
395d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._tabs = tab_list.TabList(backend.tab_list_backend)
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.credentials = browser_credentials.BrowserCredentials()
411320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.credentials.credentials_path = credentials_path
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    self._platform_backend.DidCreateBrowser(self, self._browser_backend)
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
441320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.SetReplayArchivePath(archive_path,
451320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              append_to_existing_wpr,
461320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci                              make_javascript_deterministic)
471320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
481320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    browser_options = self._browser_backend.browser_options
491320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self.platform.FlushDnsCache()
501320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    if browser_options.clear_sytem_cache_for_browser_and_profile_on_start:
511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      if self.platform.CanFlushIndividualFilesFromSystemCache():
521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self.platform.FlushSystemCacheForDirectory(
531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            self._browser_backend.profile_directory)
541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self.platform.FlushSystemCacheForDirectory(
551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci            self._browser_backend.browser_directory)
561320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci      else:
571320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci        self.platform.FlushEntireSystemCache()
581320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
591320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._browser_backend.SetBrowser(self)
601320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._browser_backend.Start()
611320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    self._platform_backend.DidStartBrowser(self, self._browser_backend)
621320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __enter__(self):
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def __exit__(self, *args):
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.Close()
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def platform(self):
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return self._platform_backend.platform
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def browser_type(self):
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._browser_backend.browser_type
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def supports_extensions(self):
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._browser_backend.supports_extensions
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def supports_tab_control(self):
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._browser_backend.supports_tab_control
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def synthetic_gesture_source_type(self):
875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self._browser_backend.browser_options.synthetic_gesture_source_type
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  @property
902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def tabs(self):
912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._tabs
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def foreground_tab(self):
955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    for i in xrange(len(self._tabs)):
965d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # The foreground tab is the first (only) one that isn't hidden.
975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # This only works through luck on Android, due to crbug.com/322544
985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # which means that tabs that have never been in the foreground return
995d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # document.hidden as false; however in current code the Android foreground
1005d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      # tab is always tab 0, which will be the first one that isn't hidden
1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if self._tabs[i].EvaluateJavaScript('!document.hidden'):
1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        return self._tabs[i]
1035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    raise Exception("No foreground tab found")
1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  @property
106a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)  @decorators.Cache
1072a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def extensions(self):
1082a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not self.supports_extensions:
1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      raise browser_backend.ExtensionsNotSupportedException(
1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)          'Extensions not supported')
111a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)    return extension_dict.ExtensionDict(self._browser_backend.extension_backend)
1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
113a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)  def _GetStatsCommon(self, pid_stats_function):
114a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    browser_pid = self._browser_backend.pid
115a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    result = {
116a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'Browser': dict(pid_stats_function(browser_pid), **{'ProcessCount': 1}),
117a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'Renderer': {'ProcessCount': 0},
118f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        'Gpu': {'ProcessCount': 0},
119f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        'Other': {'ProcessCount': 0}
120a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    }
121f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    process_count = 1
122a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    for child_pid in self._platform_backend.GetChildPids(browser_pid):
123a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      try:
124a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        child_cmd_line = self._platform_backend.GetCommandLine(child_pid)
125f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        child_stats = pid_stats_function(child_pid)
126f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      except exceptions.ProcessGoneException:
127f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        # It is perfectly fine for a process to have gone away between calling
128f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        # GetChildPids() and then further examining it.
129a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)        continue
130f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      child_process_name = self._browser_backend.GetProcessName(child_cmd_line)
131a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      process_name_type_key_map = {'gpu-process': 'Gpu', 'renderer': 'Renderer'}
132a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if child_process_name in process_name_type_key_map:
133a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        child_process_type_key = process_name_type_key_map[child_process_name]
134a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      else:
135a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        # TODO: identify other process types (zygote, plugin, etc), instead of
136f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        # lumping them in a single category.
137f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)        child_process_type_key = 'Other'
138a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      result[child_process_type_key]['ProcessCount'] += 1
139a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      for k, v in child_stats.iteritems():
140a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        if k in result[child_process_type_key]:
141a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          result[child_process_type_key][k] += v
142a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        else:
143a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          result[child_process_type_key][k] = v
144f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)      process_count += 1
145a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    for v in result.itervalues():
146a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      if v['ProcessCount'] > 1:
147a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        for k in v.keys():
148a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)          if k.endswith('Peak'):
149a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)            del v[k]
150a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      del v['ProcessCount']
151f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)    result['ProcessCount'] = process_count
152a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return result
153a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)
1542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
1552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def memory_stats(self):
1562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns a dict of memory statistics for the browser:
1572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { 'Browser': {
1585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'VM': R,
1595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'VMPeak': S,
1605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'WorkingSetSize': T,
1615d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'WorkingSetSizePeak': U,
1625d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'ProportionalSetSize': V,
1635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'PrivateDirty': W
1642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      },
165a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      'Gpu': {
1665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'VM': R,
1675d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'VMPeak': S,
1685d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'WorkingSetSize': T,
1695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'WorkingSetSizePeak': U,
1705d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'ProportionalSetSize': V,
1715d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'PrivateDirty': W
172a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      },
1732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'Renderer': {
1745d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'VM': R,
1755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'VMPeak': S,
1765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'WorkingSetSize': T,
1775d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'WorkingSetSizePeak': U,
1785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'ProportionalSetSize': V,
1795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)        'PrivateDirty': W
180a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      },
1815d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'SystemCommitCharge': X,
1825d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      'SystemTotalPhysicalMemory': Y,
183a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      'ProcessCount': Z,
1842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
1852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    Any of the above keys may be missing on a per-platform basis.
1862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
1875d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._platform_backend.PurgeUnpinnedMemory()
188a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    result = self._GetStatsCommon(self._platform_backend.GetMemoryStats)
1895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    commit_charge = self._platform_backend.GetSystemCommitCharge()
1905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if commit_charge:
1915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result['SystemCommitCharge'] = commit_charge
1925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    total = self._platform_backend.GetSystemTotalPhysicalMemory()
1935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if total:
1945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      result['SystemTotalPhysicalMemory'] = total
195a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return result
1962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
19858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  def cpu_stats(self):
19958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    """Returns a dict of cpu statistics for the system.
20058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    { 'Browser': {
20158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        'CpuProcessTime': S,
20258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        'TotalTime': T
20358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      },
20458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      'Gpu': {
20558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        'CpuProcessTime': S,
20658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        'TotalTime': T
20758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      },
20858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      'Renderer': {
20958537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        'CpuProcessTime': S,
21058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        'TotalTime': T
21158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      }
21258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    }
21358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    Any of the above keys may be missing on a per-platform basis.
21458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    """
21558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    result = self._GetStatsCommon(self._platform_backend.GetCpuStats)
21658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    del result['ProcessCount']
21758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
21858537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    # We want a single time value, not the sum for all processes.
219cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    cpu_timestamp = self._platform_backend.GetCpuTimestamp()
22058537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    for process_type in result:
22158537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      # Skip any process_types that are empty
22258537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      if not len(result[process_type]):
22358537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        continue
224cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)      result[process_type].update(cpu_timestamp)
22558537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)    return result
22658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)
22758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)  @property
2282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def io_stats(self):
2292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Returns a dict of IO statistics for the browser:
2302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    { 'Browser': {
2312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'ReadOperationCount': W,
2322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'WriteOperationCount': X,
2332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'ReadTransferCount': Y,
2342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'WriteTransferCount': Z
2352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      },
236a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      'Gpu': {
237a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'ReadOperationCount': W,
238a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'WriteOperationCount': X,
239a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'ReadTransferCount': Y,
240a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)        'WriteTransferCount': Z
241a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)      },
2422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      'Renderer': {
2432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'ReadOperationCount': W,
2442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'WriteOperationCount': X,
2452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'ReadTransferCount': Y,
2462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        'WriteTransferCount': Z
2472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      }
2482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    }
2492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """
250a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    result = self._GetStatsCommon(self._platform_backend.GetIOStats)
251a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    del result['ProcessCount']
252a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles)    return result
2532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def Close(self):
2552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    """Closes this browser."""
2565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if self._browser_backend.IsBrowserRunning():
2575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      self._platform_backend.WillCloseBrowser(self, self._browser_backend)
2588bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2592a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._wpr_server:
2602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._wpr_server.Close()
2612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._wpr_server = None
2622a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2635d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._local_server_controller.Close()
2642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._browser_backend.Close()
2652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self.credentials = None
2662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  @property
2682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def http_server(self):
2695d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self._local_server_controller.GetRunningServer(
2706e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)        memory_cache_http_server.MemoryCacheHTTPServer, None)
2712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def SetHTTPServerDirectories(self, paths):
2737d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    """Returns True if the HTTP server was started, False otherwise."""
2744e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    if isinstance(paths, basestring):
2754e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)      paths = set([paths])
2764e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)    paths = set(os.path.realpath(p) for p in paths)
2772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2788bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    # If any path is in a subdirectory of another, remove the subdirectory.
2798bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    duplicates = set()
2808bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    for parent_path in paths:
2818bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)      for sub_path in paths:
2828bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        if parent_path == sub_path:
2838bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          continue
2848bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)        if os.path.commonprefix((parent_path, sub_path)) == parent_path:
2858bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)          duplicates.add(sub_path)
2868bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)    paths -= duplicates
2878bcbed890bc3ce4d7a057a8f32cab53fa534672eTorne (Richard Coles)
2885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    if self.http_server:
2895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      if paths and self.http_server.paths == paths:
2904e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)        return False
2914e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)
2925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      self.http_server.Close()
2932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not paths:
2957d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)      return False
2962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
2975d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    server = memory_cache_http_server.MemoryCacheHTTPServer(paths)
2985d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self.StartLocalServer(server)
2997d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)    return True
3007d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)
3015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def StartLocalServer(self, server):
3025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Starts a LocalServer and associates it with this browser.
3035d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    It will be closed when the browser closes.
3055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """
3065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    self._local_server_controller.StartServer(server)
3075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  @property
3095d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)  def local_servers(self):
3105d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    """Returns the currently running local servers."""
3115d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)    return self._local_server_controller.local_servers
3125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)
3137dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def SetReplayArchivePath(self, archive_path, append_to_existing_wpr=False,
3147dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch                           make_javascript_deterministic=True):
3152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._wpr_server:
3162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._wpr_server.Close()
3172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      self._wpr_server = None
3182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not archive_path:
3202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return None
3212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if self._browser_backend.wpr_mode == wpr_modes.WPR_OFF:
3232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      return
3242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    use_record_mode = self._browser_backend.wpr_mode == wpr_modes.WPR_RECORD
3262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    if not use_record_mode:
3272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      assert os.path.isfile(archive_path)
3282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    self._wpr_server = wpr_server.ReplayServer(
3302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        self._browser_backend,
3312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        archive_path,
3322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)        use_record_mode,
3337d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)        append_to_existing_wpr,
33458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)        make_javascript_deterministic)
3352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
3362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  def GetStandardOutput(self):
3372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return self._browser_backend.GetStandardOutput()
3387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
3397dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  def GetStackTrace(self):
3407dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    return self._browser_backend.GetStackTrace()
3413551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3423551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  @property
3433551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def supports_system_info(self):
3443551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self._browser_backend.supports_system_info
3453551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3463551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  def GetSystemInfo(self):
3473551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    """Returns low-level information about the system, if available.
3483551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
3493551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)       See the documentation of the SystemInfo class for more details."""
3503551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)    return self._browser_backend.GetSystemInfo()
3511320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci
3521320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # TODO: Remove after call to Start() has been removed from
3531320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  # related authotest files.
3541320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci  def Start(self):
3551320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci    pass
356