| OLD | NEW |
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright 2017 The Chromium Authors. All rights reserved. | 2 # Copyright 2017 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 # This is intended to be a very trimmed down, single-file, hackable, and easy | 6 # This is intended to be a very trimmed down, single-file, hackable, and easy |
| 7 # to understand version of Telemetry. It's able to run simple user stories on | 7 # to understand version of Telemetry. It's able to run simple user stories on |
| 8 # Android, grab traces, and extract metrics from them. May be useful to | 8 # Android, grab traces, and extract metrics from them. May be useful to |
| 9 # diagnose issues with Chrome, reproduce regressions or prototype new user | 9 # diagnose issues with Chrome, reproduce regressions or prototype new user |
| 10 # stories. | 10 # stories. |
| (...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 383 # System Chrome app cannot be (un)installed, so we enable/disable instead. | 383 # System Chrome app cannot be (un)installed, so we enable/disable instead. |
| 384 logging.warning('Enabling %s', self.PACKAGE_NAME) | 384 logging.warning('Enabling %s', self.PACKAGE_NAME) |
| 385 self.device.RunShellCommand('pm', 'enable', self.PACKAGE_NAME) | 385 self.device.RunShellCommand('pm', 'enable', self.PACKAGE_NAME) |
| 386 | 386 |
| 387 def Uninstall(self): | 387 def Uninstall(self): |
| 388 # System Chrome app cannot be (un)installed, so we enable/disable instead. | 388 # System Chrome app cannot be (un)installed, so we enable/disable instead. |
| 389 logging.warning('Disabling %s', self.PACKAGE_NAME) | 389 logging.warning('Disabling %s', self.PACKAGE_NAME) |
| 390 self.device.RunShellCommand('pm', 'disable', self.PACKAGE_NAME) | 390 self.device.RunShellCommand('pm', 'disable', self.PACKAGE_NAME) |
| 391 | 391 |
| 392 | 392 |
| 393 class UserStory(object): |
| 394 def __init__(self, browser): |
| 395 self.device = browser.device |
| 396 self.browser = browser |
| 397 |
| 398 def GetExtraStoryApps(self): |
| 399 """Sequence of AndroidApp's, other than the browser, used in the story.""" |
| 400 return () |
| 401 |
| 402 def EnsureExtraStoryAppsClosed(self): |
| 403 running_processes = self.device.ProcessStatus() |
| 404 for app in self.GetExtraStoryApps(): |
| 405 if app.PACKAGE_NAME in running_processes: |
| 406 app.ForceStop() |
| 407 |
| 408 def Run(self, browser_flags, trace_config, trace_file): |
| 409 with self.browser.Session(browser_flags, trace_config): |
| 410 self.EnsureExtraStoryAppsClosed() |
| 411 try: |
| 412 self.RunStorySteps() |
| 413 self.browser.CollectTrace(trace_file) |
| 414 except Exception as exc: |
| 415 # Helps to pin point in the logs the moment where the story failed, |
| 416 # before any of the finally blocks get to be executed. |
| 417 logging.error('Aborting story due to %s.', type(exc).__name__) |
| 418 raise |
| 419 finally: |
| 420 self.EnsureExtraStoryAppsClosed() |
| 421 |
| 422 def RunStorySteps(self): |
| 423 """Subclasses should override this method to implement the story. |
| 424 |
| 425 The steps must: |
| 426 - at some point cause the browser to be launched, and |
| 427 - make sure the browser remains alive when done (even if backgrounded). |
| 428 """ |
| 429 raise NotImplementedError |
| 430 |
| 431 |
| 393 def ReadProcessMetrics(trace_file): | 432 def ReadProcessMetrics(trace_file): |
| 394 """Return a list of {"name": process_name, metric: value} dicts.""" | 433 """Return a list of {"name": process_name, metric: value} dicts.""" |
| 395 with open(trace_file) as f: | 434 with open(trace_file) as f: |
| 396 trace = json.load(f) | 435 trace = json.load(f) |
| 397 | 436 |
| 398 processes = collections.defaultdict(dict) | 437 processes = collections.defaultdict(dict) |
| 399 for event in trace['traceEvents']: | 438 for event in trace['traceEvents']: |
| 400 if event['ph'] == 'v': | 439 if event['ph'] == 'v': |
| 401 # Extract any metrics you may need from the trace. | 440 # Extract any metrics you may need from the trace. |
| 402 value = event['args']['dumps']['allocators'][ | 441 value = event['args']['dumps']['allocators'][ |
| 403 'java_heap/allocated_objects']['attrs']['size'] | 442 'java_heap/allocated_objects']['attrs']['size'] |
| 404 assert value['units'] == 'bytes' | 443 assert value['units'] == 'bytes' |
| 405 processes[event['pid']]['java_heap'] = int(value['value'], 16) | 444 processes[event['pid']]['java_heap'] = int(value['value'], 16) |
| 406 elif event['ph'] == 'M' and event['name'] == 'process_name': | 445 elif event['ph'] == 'M' and event['name'] == 'process_name': |
| 407 processes[event['pid']]['name'] = event['args']['name'] | 446 processes[event['pid']]['name'] = event['args']['name'] |
| 408 | 447 |
| 409 return processes.values() | 448 return processes.values() |
| OLD | NEW |