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 |