systrace: fix CRLF handling

This change cleans up the trace data processing part of systrace.py.  It also
makes the CRLF handling auto-detect the line endings of the incoming data.

Bug: 8327984
Change-Id: Ibc43f50a258ace99c09a539478c2c270e2d0a087
diff --git a/systrace.py b/systrace.py
index 621b0e8..131c589 100755
--- a/systrace.py
+++ b/systrace.py
@@ -90,69 +90,98 @@
 
   html_filename = options.output_file
 
-  trace_started = False
-  leftovers = ''
   adb = subprocess.Popen(atrace_args, stdout=subprocess.PIPE,
                          stderr=subprocess.PIPE)
-  dec = zlib.decompressobj()
-  while True:
+
+  result = None
+  data = []
+
+  # Read the text portion of the output and watch for the 'TRACE:' marker that
+  # indicates the start of the trace data.
+  while result is None:
     ready = select.select([adb.stdout, adb.stderr], [], [adb.stdout, adb.stderr])
     if adb.stderr in ready[0]:
       err = os.read(adb.stderr.fileno(), 4096)
       sys.stderr.write(err)
       sys.stderr.flush()
     if adb.stdout in ready[0]:
-      out = leftovers + os.read(adb.stdout.fileno(), 4096)
-      out = out.replace('\r\n', '\n')
-      if out.endswith('\r'):
-        out = out[:-1]
-        leftovers = '\r'
-      else:
-        leftovers = ''
-      if not trace_started:
-        lines = out.splitlines(True)
-        out = ''
-        for i, line in enumerate(lines):
-          if line == 'TRACE:\n':
-            sys.stdout.write("downloading trace...")
-            sys.stdout.flush()
-            out = ''.join(lines[i+1:])
-            html_file = open(html_filename, 'w')
-            html_file.write(html_prefix % (css, js))
-            trace_started = True
-            break
-          elif 'TRACE:'.startswith(line) and i == len(lines) - 1:
-            leftovers = line + leftovers
-          else:
-            sys.stdout.write(line)
-            sys.stdout.flush()
-      if len(out) > 0:
-        out = dec.decompress(out)
-      html_out = out.replace('\n', '\\n\\\n')
-      if len(html_out) > 0:
-        html_file.write(html_out)
+      out = os.read(adb.stdout.fileno(), 4096)
+      parts = out.split('\nTRACE:', 1)
+
+      txt = parts[0].replace('\r', '')
+      if len(parts) == 2:
+        # The '\nTRACE:' match stole the last newline from the text, so add it
+        # back here.
+        txt += '\n'
+      sys.stdout.write(txt)
+      sys.stdout.flush()
+
+      if len(parts) == 2:
+        data.append(parts[1])
+        sys.stdout.write("downloading trace...")
+        sys.stdout.flush()
+        break
+
     result = adb.poll()
-    if result is not None:
-      break
-  if result != 0:
-    print >> sys.stderr, 'adb returned error code %d' % result
-  elif trace_started:
-    html_out = dec.flush().replace('\n', '\\n\\\n').replace('\r', '')
-    if len(html_out) > 0:
+
+  # Read and buffer the data portion of the output.
+  while result is None:
+    ready = select.select([adb.stdout, adb.stderr], [], [adb.stdout, adb.stderr])
+    if adb.stderr in ready[0]:
+      err = os.read(adb.stderr.fileno(), 4096)
+      sys.stderr.write(err)
+      sys.stderr.flush()
+    if adb.stdout in ready[0]:
+      out = os.read(adb.stdout.fileno(), 4096)
+      data.append(out)
+
+    result = adb.poll()
+
+  if result == 0:
+    if expect_trace:
+      data = ''.join(data)
+
+      # Collapse CRLFs that are added by adb shell.
+      if data.startswith('\r\n'):
+        data = data.replace('\r\n', '\n')
+
+      # Skip the initial newline.
+      data = data[1:]
+
+      if not data:
+        print >> sys.stderr, ('No data was captured.  Output file was not ' +
+          'written.')
+        sys.exit(1)
+      else:
+        # Indicate to the user that the data download is complete.
+        print " done\n"
+
+      html_file = open(html_filename, 'w')
+      html_file.write(html_prefix % (css, js))
+
+      size = 4096
+      dec = zlib.decompressobj()
+      for chunk in (data[i:i+size] for i in xrange(0, len(data), size)):
+        decoded_chunk = dec.decompress(chunk)
+        html_chunk = decoded_chunk.replace('\n', '\\n\\\n')
+        html_file.write(html_chunk)
+
+      html_out = dec.flush().replace('\n', '\\n\\\n')
       html_file.write(html_out)
-    html_file.write(html_suffix)
-    html_file.close()
-    print " done\n\n    wrote file://%s/%s\n" % (os.getcwd(), options.output_file)
-  elif expect_trace:
-    print >> sys.stderr, ('An error occured while capturing the trace.  Output ' +
-      'file was not written.')
+      html_file.write(html_suffix)
+      html_file.close()
+      print "\n    wrote file://%s/%s\n" % (os.getcwd(), options.output_file)
+
+  else: # i.e. result != 0
+    print >> sys.stderr, 'adb returned error code %d' % result
+    sys.exit(1)
 
 def get_assets(src_dir, build_dir):
   sys.path.append(build_dir)
   gen = __import__('generate_standalone_timeline_view', {}, {})
   parse_deps = __import__('parse_deps', {}, {})
   filenames = gen._get_input_filenames()
-  load_sequence = parse_deps.calc_load_sequence(filenames)
+  load_sequence = parse_deps.calc_load_sequence(filenames, src_dir)
 
   js_files = []
   js_flattenizer = "window.FLATTENED = {};\n"