Store profile report for each build in run_on_as_app.py

Bug: 122586281
Change-Id: Ia144bb6ed407cf601bdef64dc2418305dab10efc
diff --git a/tools/as_utils.py b/tools/as_utils.py
index 7b373f4..d5db8a3 100644
--- a/tools/as_utils.py
+++ b/tools/as_utils.py
@@ -5,6 +5,7 @@
 
 from distutils.version import LooseVersion
 import os
+import shutil
 
 import utils
 
@@ -62,3 +63,43 @@
     for line in lines:
       if (utils.R8_JAR not in line) and (utils.R8LIB_JAR not in line):
         f.write(line)
+
+def Move(src, dst):
+  print('Moving `{}` to `{}`'.format(src, dst))
+  dst_parent = os.path.dirname(dst)
+  if not os.path.isdir(dst_parent):
+    os.makedirs(dst_parent)
+  elif os.path.isdir(dst):
+    shutil.rmtree(dst)
+  elif os.path.isfile(dst):
+    os.remove(dst)
+  os.rename(src, dst)
+
+def MoveDir(src, dst):
+  assert os.path.isdir(src)
+  Move(src, dst)
+
+def MoveFile(src, dst):
+  assert os.path.isfile(src)
+  Move(src, dst)
+
+def MoveProfileReportTo(dest_dir, build_stdout):
+  html_file = None
+  profile_message = 'See the profiling report at: '
+  for line in build_stdout:
+    if profile_message in line:
+      html_file = line[len(profile_message):]
+      if html_file.startswith('file://'):
+        html_file = html_file[len('file://'):]
+      break
+
+  if not html_file:
+    return
+
+  assert os.path.isfile(html_file), 'Expected to find HTML file at {}'.format(
+      html_file)
+  MoveFile(html_file, os.path.join(dest_dir, 'index.html'))
+
+  html_dir = os.path.dirname(html_file)
+  for dir_name in ['css', 'js']:
+    MoveDir(os.path.join(html_dir, dir_name), os.path.join(dest_dir, dir_name))
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index 244c093..eab815d 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -123,13 +123,6 @@
 def GitCheckout(file):
   return subprocess.check_output(['git', 'checkout', file]).strip()
 
-def MoveApkToDest(apk, apk_dest):
-  print('Moving `{}` to `{}`'.format(apk, apk_dest))
-  assert os.path.isfile(apk)
-  if os.path.isfile(apk_dest):
-    os.remove(apk_dest)
-  os.rename(apk, apk_dest)
-
 def InstallApkOnEmulator(apk_dest):
   subprocess.check_call(
       ['adb', '-s', emulator_id, 'install', '-r', '-d', apk_dest])
@@ -196,14 +189,17 @@
       apk_dest = None
       result = {}
       try:
-        apk_dest = BuildAppWithShrinker(
+        (apk_dest, profile_dest_dir) = BuildAppWithShrinker(
           app, config, shrinker, checkout_dir, options)
         dex_size = ComputeSizeOfDexFilesInApk(apk_dest)
         result['apk_dest'] = apk_dest,
         result['build_status'] = 'success'
         result['dex_size'] = dex_size
-      except:
+        result['profile_dest_dir'] = profile_dest_dir
+      except Exception as e:
         warn('Failed to build {} with {}'.format(app, shrinker))
+        if e:
+          print('Error: ' + str(e))
         result['build_status'] = 'failed'
 
       if options.monkey:
@@ -255,9 +251,20 @@
     releaseTarget = app_module + ':' + 'assemble' + (
         flavor.capitalize() if flavor else '') + 'Release'
 
-  cmd = ['./gradlew', '--no-daemon', 'clean', releaseTarget, '--stacktrace']
+  cmd = ['./gradlew', '--no-daemon', 'clean', releaseTarget, '--profile',
+      '--stacktrace']
+
   utils.PrintCmd(cmd)
-  subprocess.check_call(cmd, env=env)
+  build_process = subprocess.Popen(cmd, env=env, stdout=subprocess.PIPE)
+  stdout = []
+  while True:
+    line = build_process.stdout.readline()
+    if line != b'':
+      stripped = line.rstrip()
+      stdout.append(stripped)
+      print(stripped)
+    else:
+      break
 
   apk_base_name = (archives_base_name
       + (('-' + flavor) if flavor else '') + '-release')
@@ -288,15 +295,18 @@
 
   if os.path.isfile(signed_apk):
     apk_dest = os.path.join(out, signed_apk_name)
-    MoveApkToDest(signed_apk, apk_dest)
+    as_utils.MoveFile(signed_apk, apk_dest)
   else:
     apk_dest = os.path.join(out, unsigned_apk_name)
-    MoveApkToDest(unsigned_apk, apk_dest)
+    as_utils.MoveFile(unsigned_apk, apk_dest)
 
   assert IsBuiltWithR8(apk_dest) == ('r8' in shrinker), (
       'Unexpected marker in generated APK for {}'.format(shrinker))
 
-  return apk_dest
+  profile_dest_dir = os.path.join(out, 'profile')
+  as_utils.MoveProfileReportTo(profile_dest_dir, stdout)
+
+  return (apk_dest, profile_dest_dir)
 
 def RunMonkey(app, config, apk_dest):
   WaitForEmulator()