1927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis#!/usr/bin/env python
2927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
34b56a2b4acaf00b9c299ab378b52ad8d16c8bc0bJamie Gennis# Copyright (c) 2011 The Chromium Authors. All rights reserved.
44b56a2b4acaf00b9c299ab378b52ad8d16c8bc0bJamie Gennis# Use of this source code is governed by a BSD-style license that can be
54b56a2b4acaf00b9c299ab378b52ad8d16c8bc0bJamie Gennis# found in the LICENSE file.
6927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
7927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis"""Android system-wide tracing utility.
8927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
9927914761ffb4ead9d21132154c35d56b6bed787Jamie GennisThis is a tool for capturing a trace that includes data from both userland and
10927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennisthe kernel.  It creates an HTML file for visualizing the trace.
11927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis"""
12927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
132da489cd246702bee5938545b18a6f710ed214bcJamie Gennisimport errno, optparse, os, select, subprocess, sys, time, zlib
14927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
152da489cd246702bee5938545b18a6f710ed214bcJamie Gennisflattened_css_file = 'style.css'
162da489cd246702bee5938545b18a6f710ed214bcJamie Gennisflattened_js_file = 'script.js'
172da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
18664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennisclass OptionParserIgnoreErrors(optparse.OptionParser):
19664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  def error(self, msg):
20664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    pass
21664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
22664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  def exit(self):
23664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    pass
24664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
25664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  def print_usage(self):
26664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    pass
27664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
28664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  def print_help(self):
29664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    pass
30664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
31664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  def print_version(self):
32664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    pass
33664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
34664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennisdef get_device_sdk_version():
35664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  getprop_args = ['adb', 'shell', 'getprop', 'ro.build.version.sdk']
36664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
37664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  parser = OptionParserIgnoreErrors()
38664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  parser.add_option('-e', '--serial', dest='device_serial', type='string')
39664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  options, args = parser.parse_args()
40664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  if options.device_serial is not None:
41664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    getprop_args[1:1] = ['-s', options.device_serial]
42664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
43c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis  adb = subprocess.Popen(getprop_args, stdout=subprocess.PIPE,
44c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis                         stderr=subprocess.PIPE)
45c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis  out, err = adb.communicate()
46c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis  if adb.returncode != 0:
47c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis    print >> sys.stderr, 'Error querying device SDK-version:'
48c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis    print >> sys.stderr, err
49c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis    sys.exit(1)
50c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis
51c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis  version = int(out)
52c2a6cae574b71b4b42c8bbbde17ea8796121f0deJamie Gennis  return version
53664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
54de427befa61d2a540c96fa8f19109293e6f566a6Keun young Parkdef add_adb_serial(command, serial):
55de427befa61d2a540c96fa8f19109293e6f566a6Keun young Park  if serial != None:
56de427befa61d2a540c96fa8f19109293e6f566a6Keun young Park    command.insert(1, serial)
57de427befa61d2a540c96fa8f19109293e6f566a6Keun young Park    command.insert(1, '-s')
58de427befa61d2a540c96fa8f19109293e6f566a6Keun young Park
59927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennisdef main():
60664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  device_sdk_version = get_device_sdk_version()
61664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis  if device_sdk_version < 18:
62664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    legacy_script = os.path.join(os.path.dirname(sys.argv[0]), 'systrace-legacy.py')
63664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis    os.execv(legacy_script, sys.argv)
64664f21bcaf14044e5e9b09cb7beb8724d18fb851Jamie Gennis
65fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  usage = "Usage: %prog [options] [category1 [category2 ...]]"
66fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  desc = "Example: %prog -b 32768 -t 15 gfx input view sched freq"
67fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  parser = optparse.OptionParser(usage=usage, description=desc)
68927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  parser.add_option('-o', dest='output_file', help='write HTML to FILE',
69927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis                    default='trace.html', metavar='FILE')
70927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  parser.add_option('-t', '--time', dest='trace_time', type='int',
71927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis                    help='trace for N seconds', metavar='N')
7298ef97d452aec9ef13a159cb7db96a347b3b2190Jamie Gennis  parser.add_option('-b', '--buf-size', dest='trace_buf_size', type='int',
7398ef97d452aec9ef13a159cb7db96a347b3b2190Jamie Gennis                    help='use a trace buffer size of N KB', metavar='N')
74553ec569391f19c1a0711b42fc89a03d3e670009Jamie Gennis  parser.add_option('-k', '--ktrace', dest='kfuncs', action='store',
75553ec569391f19c1a0711b42fc89a03d3e670009Jamie Gennis                    help='specify a comma-separated list of kernel functions to trace')
76fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  parser.add_option('-l', '--list-categories', dest='list_categories', default=False,
77fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis                    action='store_true', help='list the available categories and exit')
78b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis  parser.add_option('-a', '--app', dest='app_name', default=None, type='string',
79b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis                    action='store', help='enable application-level tracing for comma-separated ' +
80b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis                    'list of app cmdlines')
81fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis
82595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown  parser.add_option('--link-assets', dest='link_assets', default=False,
83595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown                    action='store_true', help='link to original CSS or JS resources '
84595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown                    'instead of embedding them')
85a0cfa1db34523c908b00b443d227b6a516ce2010Glenn Kasten  parser.add_option('--from-file', dest='from_file', action='store',
86340d772e8dc47929a927399a343d2218f6f5672cXia Wang                    help='read the trace from a file (compressed) rather than running a live trace')
872da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  parser.add_option('--asset-dir', dest='asset_dir', default='trace-viewer',
882da489cd246702bee5938545b18a6f710ed214bcJamie Gennis                    type='string', help='')
89de427befa61d2a540c96fa8f19109293e6f566a6Keun young Park  parser.add_option('-e', '--serial', dest='device_serial', type='string',
90de427befa61d2a540c96fa8f19109293e6f566a6Keun young Park                    help='adb device serial number')
91fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis
92927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  options, args = parser.parse_args()
93927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
94fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  if options.list_categories:
95fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    atrace_args = ['adb', 'shell', 'atrace', '--list_categories']
96fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    expect_trace = False
97fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  elif options.from_file is not None:
98a0cfa1db34523c908b00b443d227b6a516ce2010Glenn Kasten    atrace_args = ['cat', options.from_file]
99fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    expect_trace = True
100fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  else:
101fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    atrace_args = ['adb', 'shell', 'atrace', '-z']
102fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    expect_trace = True
103fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis
104fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    if options.trace_time is not None:
105fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis      if options.trace_time > 0:
106fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis        atrace_args.extend(['-t', str(options.trace_time)])
107fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis      else:
108fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis        parser.error('the trace time must be a positive number')
109b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis
110fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    if options.trace_buf_size is not None:
111fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis      if options.trace_buf_size > 0:
112fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis        atrace_args.extend(['-b', str(options.trace_buf_size)])
113fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis      else:
114fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis        parser.error('the trace buffer size must be a positive number')
115fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis
116b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis    if options.app_name is not None:
117b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis      atrace_args.extend(['-a', options.app_name])
118b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis
119553ec569391f19c1a0711b42fc89a03d3e670009Jamie Gennis    if options.kfuncs is not None:
120553ec569391f19c1a0711b42fc89a03d3e670009Jamie Gennis      atrace_args.extend(['-k', options.kfuncs])
121553ec569391f19c1a0711b42fc89a03d3e670009Jamie Gennis
122fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    atrace_args.extend(args)
123fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis
124fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis  if atrace_args[0] == 'adb':
125fe4c594d0d9cd87bb0ca43c2b172ec4ab5079ae9Jamie Gennis    add_adb_serial(atrace_args, options.device_serial)
126a0cfa1db34523c908b00b443d227b6a516ce2010Glenn Kasten
1274b56a2b4acaf00b9c299ab378b52ad8d16c8bc0bJamie Gennis  script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
128595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown
129595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown  if options.link_assets:
1302da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    src_dir = os.path.join(script_dir, options.asset_dir, 'src')
1312da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    build_dir = os.path.join(script_dir, options.asset_dir, 'build')
1322da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1332da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    js_files, js_flattenizer, css_files = get_assets(src_dir, build_dir)
1342da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
1352da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    css = '\n'.join(linked_css_tag % (os.path.join(src_dir, f)) for f in css_files)
1362da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    js = '<script language="javascript">\n%s</script>\n' % js_flattenizer
1372da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    js += '\n'.join(linked_js_tag % (os.path.join(src_dir, f)) for f in js_files)
138595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown  else:
1392da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    css_filename = os.path.join(script_dir, flattened_css_file)
1402da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    js_filename = os.path.join(script_dir, flattened_js_file)
141595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown    css = compiled_css_tag % (open(css_filename).read())
142595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown    js = compiled_js_tag % (open(js_filename).read())
1434b56a2b4acaf00b9c299ab378b52ad8d16c8bc0bJamie Gennis
144927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  html_filename = options.output_file
145927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
1461bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis  adb = subprocess.Popen(atrace_args, stdout=subprocess.PIPE,
1477e3783f4610cd922712bb67b5ba4c95ed2e71ddbJamie Gennis                         stderr=subprocess.PIPE)
1489623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
1499623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  result = None
1509623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  data = []
1519623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
1529623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  # Read the text portion of the output and watch for the 'TRACE:' marker that
1539623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  # indicates the start of the trace data.
1549623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  while result is None:
1551bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis    ready = select.select([adb.stdout, adb.stderr], [], [adb.stdout, adb.stderr])
1561bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis    if adb.stderr in ready[0]:
1571bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis      err = os.read(adb.stderr.fileno(), 4096)
1581bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis      sys.stderr.write(err)
1591bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis      sys.stderr.flush()
1601bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis    if adb.stdout in ready[0]:
1619623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      out = os.read(adb.stdout.fileno(), 4096)
1629623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      parts = out.split('\nTRACE:', 1)
1639623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
1649623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      txt = parts[0].replace('\r', '')
1659623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      if len(parts) == 2:
1669623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        # The '\nTRACE:' match stole the last newline from the text, so add it
1679623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        # back here.
1689623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        txt += '\n'
1699623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      sys.stdout.write(txt)
1709623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      sys.stdout.flush()
1719623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
1729623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      if len(parts) == 2:
1739623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        data.append(parts[1])
1749623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        sys.stdout.write("downloading trace...")
1759623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        sys.stdout.flush()
1769623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        break
1779623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
1781bf4a4963a2970b80941691b4901e17a47037bd3Jamie Gennis    result = adb.poll()
1799623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
1809623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  # Read and buffer the data portion of the output.
18118bb528287dd9407583346b9826de4a433481131Jamie Gennis  while True:
1829623f136353986b8248e485e7af87661e0b13d54Jamie Gennis    ready = select.select([adb.stdout, adb.stderr], [], [adb.stdout, adb.stderr])
18318bb528287dd9407583346b9826de4a433481131Jamie Gennis    keepReading = False
1849623f136353986b8248e485e7af87661e0b13d54Jamie Gennis    if adb.stderr in ready[0]:
1859623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      err = os.read(adb.stderr.fileno(), 4096)
18618bb528287dd9407583346b9826de4a433481131Jamie Gennis      if len(err) > 0:
18718bb528287dd9407583346b9826de4a433481131Jamie Gennis        keepReading = True
18818bb528287dd9407583346b9826de4a433481131Jamie Gennis        sys.stderr.write(err)
18918bb528287dd9407583346b9826de4a433481131Jamie Gennis        sys.stderr.flush()
1909623f136353986b8248e485e7af87661e0b13d54Jamie Gennis    if adb.stdout in ready[0]:
1919623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      out = os.read(adb.stdout.fileno(), 4096)
19218bb528287dd9407583346b9826de4a433481131Jamie Gennis      if len(out) > 0:
19318bb528287dd9407583346b9826de4a433481131Jamie Gennis        keepReading = True
19418bb528287dd9407583346b9826de4a433481131Jamie Gennis        data.append(out)
19518bb528287dd9407583346b9826de4a433481131Jamie Gennis
19618bb528287dd9407583346b9826de4a433481131Jamie Gennis    if result is not None and not keepReading:
19718bb528287dd9407583346b9826de4a433481131Jamie Gennis      break
1989623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
1999623f136353986b8248e485e7af87661e0b13d54Jamie Gennis    result = adb.poll()
2009623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2019623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  if result == 0:
2029623f136353986b8248e485e7af87661e0b13d54Jamie Gennis    if expect_trace:
2039623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      data = ''.join(data)
2049623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2059623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      # Collapse CRLFs that are added by adb shell.
2069623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      if data.startswith('\r\n'):
2079623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        data = data.replace('\r\n', '\n')
2089623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2099623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      # Skip the initial newline.
2109623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      data = data[1:]
2119623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2129623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      if not data:
2139623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        print >> sys.stderr, ('No data was captured.  Output file was not ' +
2149623f136353986b8248e485e7af87661e0b13d54Jamie Gennis          'written.')
2159623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        sys.exit(1)
2169623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      else:
2179623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        # Indicate to the user that the data download is complete.
2189623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        print " done\n"
2199623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2209623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      html_file = open(html_filename, 'w')
2219623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      html_file.write(html_prefix % (css, js))
2229623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2239623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      size = 4096
2249623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      dec = zlib.decompressobj()
2259623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      for chunk in (data[i:i+size] for i in xrange(0, len(data), size)):
2269623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        decoded_chunk = dec.decompress(chunk)
2279623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        html_chunk = decoded_chunk.replace('\n', '\\n\\\n')
2289623f136353986b8248e485e7af87661e0b13d54Jamie Gennis        html_file.write(html_chunk)
2299623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2309623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      html_out = dec.flush().replace('\n', '\\n\\\n')
231bf3e61646bc175280d3a23f465a30590238c684cJamie Gennis      html_file.write(html_out)
2329623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      html_file.write(html_suffix)
2339623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      html_file.close()
2349623f136353986b8248e485e7af87661e0b13d54Jamie Gennis      print "\n    wrote file://%s/%s\n" % (os.getcwd(), options.output_file)
2359623f136353986b8248e485e7af87661e0b13d54Jamie Gennis
2369623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  else: # i.e. result != 0
2379623f136353986b8248e485e7af87661e0b13d54Jamie Gennis    print >> sys.stderr, 'adb returned error code %d' % result
2389623f136353986b8248e485e7af87661e0b13d54Jamie Gennis    sys.exit(1)
239927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
2402da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdef get_assets(src_dir, build_dir):
2412da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  sys.path.append(build_dir)
2422da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  gen = __import__('generate_standalone_timeline_view', {}, {})
2432da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  parse_deps = __import__('parse_deps', {}, {})
2442da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  filenames = gen._get_input_filenames()
2459623f136353986b8248e485e7af87661e0b13d54Jamie Gennis  load_sequence = parse_deps.calc_load_sequence(filenames, src_dir)
2462da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2472da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  js_files = []
2482da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  js_flattenizer = "window.FLATTENED = {};\n"
2492da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  css_files = []
2502da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2512da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  for module in load_sequence:
2522da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    js_files.append(os.path.relpath(module.filename, src_dir))
2532da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    js_flattenizer += "window.FLATTENED['%s'] = true;\n" % module.name
2542da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    for style_sheet in module.style_sheets:
2552da489cd246702bee5938545b18a6f710ed214bcJamie Gennis      css_files.append(os.path.relpath(style_sheet.filename, src_dir))
2562da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2572da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  sys.path.pop()
2582da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
2592da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  return (js_files, js_flattenizer, css_files)
2602da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
261927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennishtml_prefix = """<!DOCTYPE HTML>
262927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis<html>
263927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis<head i18n-values="dir:textdirection;">
264b9a5fc88b96d2cd8f6b08c72cc35917e42367969Jamie Gennis<meta charset="utf-8"/>
265927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis<title>Android System Trace</title>
266595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown%s
267595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown%s
2682da489cd246702bee5938545b18a6f710ed214bcJamie Gennis<script language="javascript">
2692da489cd246702bee5938545b18a6f710ed214bcJamie Gennisdocument.addEventListener('DOMContentLoaded', function() {
2702da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  if (!linuxPerfData)
2712da489cd246702bee5938545b18a6f710ed214bcJamie Gennis    return;
2722da489cd246702bee5938545b18a6f710ed214bcJamie Gennis
27388448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  var m = new tracing.Model(linuxPerfData);
2742da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  var timelineViewEl = document.querySelector('.view');
27588448d9ae4dfff1805045790ef5f32495d62abccJeff Brown  tracing.ui.decorate(timelineViewEl, tracing.TimelineView);
2762da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  timelineViewEl.model = m;
2772da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  timelineViewEl.tabIndex = 1;
2782da489cd246702bee5938545b18a6f710ed214bcJamie Gennis  timelineViewEl.timeline.focusElement = timelineViewEl;
2792da489cd246702bee5938545b18a6f710ed214bcJamie Gennis});
2802da489cd246702bee5938545b18a6f710ed214bcJamie Gennis</script>
281927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis<style>
282927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  .view {
283927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis    overflow: hidden;
284927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis    position: absolute;
285927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis    top: 0;
286927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis    bottom: 0;
287927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis    left: 0;
288927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis    right: 0;
289927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  }
290927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis</style>
291927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis</head>
292927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis<body>
293927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  <div class="view">
294927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  </div>
2952da489cd246702bee5938545b18a6f710ed214bcJamie Gennis<!-- BEGIN TRACE -->
296927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  <script>
297927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  var linuxPerfData = "\\
298927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis"""
299927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
3002da489cd246702bee5938545b18a6f710ed214bcJamie Gennishtml_suffix = """\\n";
301927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  </script>
3022da489cd246702bee5938545b18a6f710ed214bcJamie Gennis<!-- END TRACE -->
303927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis</body>
304927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis</html>
305927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis"""
306927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis
307595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Browncompiled_css_tag = """<style type="text/css">%s</style>"""
308595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Browncompiled_js_tag = """<script language="javascript">%s</script>"""
309595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown
310595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brownlinked_css_tag = """<link rel="stylesheet" href="%s"></link>"""
311595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brownlinked_js_tag = """<script language="javascript" src="%s"></script>"""
312595ae1e4b47b4a51f2339c2672e63c17d4922a95Jeff Brown
313927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennisif __name__ == '__main__':
314927914761ffb4ead9d21132154c35d56b6bed787Jamie Gennis  main()
315