1# Copyright 2013 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import os
6import StringIO
7import subprocess
8import zipfile
9
10from telemetry.core import util
11from telemetry.internal.backends.chrome import android_browser_finder
12from telemetry.internal.platform import profiler
13from telemetry.timeline import trace_data as trace_data_module
14from telemetry.timeline import tracing_config
15
16_SYSTRACE_CATEGORIES = [
17    'gfx',
18    'input',
19    'view',
20    'sched',
21    'freq',
22]
23
24class AndroidSystraceProfiler(profiler.Profiler):
25  """Collects a Systrace on Android."""
26
27  def __init__(self, browser_backend, platform_backend, output_path, state,
28               device=None):
29    super(AndroidSystraceProfiler, self).__init__(
30        browser_backend, platform_backend, output_path, state)
31    assert self._browser_backend.supports_tracing
32    self._output_path = output_path + '-trace.zip'
33    self._systrace_output_path = output_path + '.systrace'
34
35    # Use telemetry's own tracing backend instead the combined mode in
36    # adb_profile_chrome because some benchmarks also do tracing of their own
37    # and the two methods conflict.
38    config = tracing_config.TracingConfig()
39    config.enable_chrome_trace = True
40    self._browser_backend.StartTracing(config, timeout=10)
41    command = ['python', os.path.join(util.GetCatapultDir(), 'systrace', 'bin',
42                                      'adb_profile_chrome'),
43               '--categories', '', '--continuous', '--output',
44               self._systrace_output_path, '--json', '--systrace',
45               ','.join(_SYSTRACE_CATEGORIES)]
46    if device:
47      command.extend(['--device', device])
48    self._profiler = subprocess.Popen(command, stdin=subprocess.PIPE,
49                                      stdout=subprocess.PIPE)
50
51  @classmethod
52  def name(cls):
53    return 'android-systrace'
54
55  @classmethod
56  def is_supported(cls, browser_type):
57    if browser_type == 'any':
58      return android_browser_finder.CanFindAvailableBrowsers()
59    return browser_type.startswith('android')
60
61  def CollectProfile(self):
62    self._profiler.communicate(input='\n')
63    trace_result_builder = trace_data_module.TraceDataBuilder()
64    self._browser_backend.StopTracing(trace_result_builder)
65    trace_result = trace_result_builder.AsData()
66
67    trace_file = StringIO.StringIO()
68    trace_result.Serialize(trace_file)
69
70    # Merge the chrome and systraces into a zip file.
71    with zipfile.ZipFile(self._output_path, 'w', zipfile.ZIP_DEFLATED) as z:
72      z.writestr('trace.json', trace_file.getvalue())
73      z.write(self._systrace_output_path, 'systrace')
74      os.unlink(self._systrace_output_path)
75
76    print 'Systrace saved as %s' % self._output_path
77    print 'To view, open in chrome://tracing'
78    return [self._output_path]
79