Merge "Don't warn on missing desugared java8 methods"
diff --git a/tools/as_utils.py b/tools/as_utils.py
index b4eb396..9c2c8c8 100644
--- a/tools/as_utils.py
+++ b/tools/as_utils.py
@@ -10,9 +10,10 @@
 
 import utils
 
-def add_r8_dependency(checkout_dir, minified):
+def add_r8_dependency(checkout_dir, temp_dir, minified):
   build_file = os.path.join(checkout_dir, 'build.gradle')
-  assert os.path.isfile(build_file), 'Expected a file to be present at {}'.format(build_file)
+  assert os.path.isfile(build_file), (
+      'Expected a file to be present at {}'.format(build_file))
 
   with open(build_file) as f:
     lines = f.readlines()
@@ -25,15 +26,16 @@
     for line in lines:
       stripped = line.strip()
       if stripped == 'dependencies {':
-        assert not is_inside_dependencies, 'Unexpected line with \'dependencies {\''
+        assert not is_inside_dependencies, (
+            'Unexpected line with \'dependencies {\'')
         is_inside_dependencies = True
       if is_inside_dependencies:
-        if utils.R8_JAR in stripped:
+        if '/r8.jar' in stripped:
           if minified:
             # Skip line to avoid dependency on r8.jar
             continue
           added_r8_dependency = True
-        elif utils.R8LIB_JAR in stripped:
+        elif '/r8lib.jar' in stripped:
           if not minified:
             # Skip line to avoid dependency on r8lib.jar
             continue
@@ -42,7 +44,7 @@
           gradle_version = stripped[stripped.rindex(':')+1:-1]
           if not added_r8_dependency:
             indent = ''.ljust(line.index('classpath'))
-            jar = utils.R8LIB_JAR if minified else utils.R8_JAR
+            jar = os.path.join(temp_dir, 'r8lib.jar' if minified else 'r8.jar')
             f.write('{}classpath files(\'{}\')\n'.format(indent, jar))
             added_r8_dependency = True
         elif stripped == '}':
@@ -63,45 +65,38 @@
     lines = f.readlines()
   with open(build_file, 'w') as f:
     for line in lines:
-      if (utils.R8_JAR not in line) and (utils.R8LIB_JAR not in line):
+      if ('/r8.jar' not in line) and ('/r8lib.jar' not in line):
         f.write(line)
 
 def GetMinAndCompileSdk(app, config, checkout_dir, apk_reference):
-  app_module = config.get('app_module', 'app')
-  build_gradle_file = os.path.join(checkout_dir, app_module, 'build.gradle')
-  assert os.path.isfile(build_gradle_file), (
-      'Expected to find build.gradle file at {}'.format(build_gradle_file))
 
-  compile_sdk = None
-  min_sdks = []
-  target_sdk = None
+  compile_sdk = config.get('compile_sdk', None)
+  min_sdk = config.get('min_sdk', None)
 
-  with open(build_gradle_file) as f:
-    for line in f.readlines():
-      stripped = line.strip()
-      if stripped.startswith('compileSdkVersion '):
-        assert not compile_sdk
-        compile_sdk = int(stripped[len('compileSdkVersion '):])
-      if stripped.startswith('minSdkVersion '):
-        min_sdks.append(int(stripped[len('minSdkVersion '):]))
-      elif stripped.startswith('targetSdkVersion '):
-        assert not target_sdk
-        target_sdk = int(stripped[len('targetSdkVersion '):])
+  if not compile_sdk or not min_sdk:
+    app_module = config.get('app_module', 'app')
+    build_gradle_file = os.path.join(checkout_dir, app_module, 'build.gradle')
+    assert os.path.isfile(build_gradle_file), (
+        'Expected to find build.gradle file at {}'.format(build_gradle_file))
 
-  if len(min_sdks) == 1:
-    min_sdk = min_sdks[0]
-  else:
-    assert 'min_sdk' in config
-    min_sdk = config.get('min_sdk')
+    # Attempt to find the sdk values from build.gradle.
+    with open(build_gradle_file) as f:
+      for line in f.readlines():
+        stripped = line.strip()
+        if stripped.startswith('compileSdkVersion '):
+          if 'compile_sdk' not in config:
+            assert not compile_sdk
+            compile_sdk = int(stripped[len('compileSdkVersion '):])
+        elif stripped.startswith('minSdkVersion '):
+          if 'min_sdk' not in config:
+            assert not min_sdk
+            min_sdk = int(stripped[len('minSdkVersion '):])
 
   assert min_sdk, (
       'Expected to find `minSdkVersion` in {}'.format(build_gradle_file))
   assert compile_sdk, (
       'Expected to find `compileSdkVersion` in {}'.format(build_gradle_file))
 
-  assert not target_sdk or target_sdk == compile_sdk, (
-      'Expected `compileSdkVersion` and `targetSdkVersion` to be the same')
-
   return (min_sdk, compile_sdk)
 
 def IsGradleTaskName(x):
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index fcd0a76..128b6e3 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -8,9 +8,9 @@
 import gradle
 import os
 import optparse
+import shutil
 import subprocess
 import sys
-import tempfile
 import time
 import utils
 import zipfile
@@ -36,6 +36,7 @@
       'git_repo': 'https://github.com/christofferqa/AnExplorer',
       'flavor': 'googleMobilePro',
       'signed-apk-name': 'AnExplorer-googleMobileProRelease-4.0.3.apk',
+      'min_sdk': 17
   },
   'AntennaPod': {
       'app_id': 'de.danoeh.antennapod',
@@ -127,9 +128,18 @@
       dex_size += z.getinfo(filename).file_size
   return dex_size
 
-def IsBuiltWithR8(apk):
-  script = os.path.join(utils.TOOLS_DIR, 'extractmarker.py')
-  return '~~R8' in subprocess.check_output(['python', script, apk]).strip()
+def IsBuiltWithR8(apk, temp_dir):
+  r8_jar = os.path.join(temp_dir, 'r8.jar')
+
+  # Use the copy of r8.jar if it is there.
+  if os.path.isfile(r8_jar):
+    cmd = ['java', '-ea', '-jar', r8_jar, 'extractmarker', apk]
+  else:
+    script = os.path.join(utils.TOOLS_DIR, 'extractmarker.py')
+    cmd = ['python', script, apk]
+
+  utils.PrintCmd(cmd)
+  return '~~R8' in subprocess.check_output(cmd).strip()
 
 def IsMinifiedR8(shrinker):
   return shrinker == 'r8-minified' or shrinker == 'r8full-minified'
@@ -196,7 +206,7 @@
     else:
       return True
 
-def GetResultsForApp(app, config, options):
+def GetResultsForApp(app, config, options, temp_dir):
   git_repo = config['git_repo']
 
   # Checkout and build in the build directory.
@@ -221,13 +231,13 @@
   result['status'] = 'success'
 
   result_per_shrinker = BuildAppWithSelectedShrinkers(
-      app, config, options, checkout_dir)
+      app, config, options, checkout_dir, temp_dir)
   for shrinker, shrinker_result in result_per_shrinker.iteritems():
     result[shrinker] = shrinker_result
 
   return result
 
-def BuildAppWithSelectedShrinkers(app, config, options, checkout_dir):
+def BuildAppWithSelectedShrinkers(app, config, options, checkout_dir, temp_dir):
   result_per_shrinker = {}
 
   with utils.ChangedWorkingDirectory(checkout_dir):
@@ -242,7 +252,7 @@
         out_dir = os.path.join(checkout_dir, 'out', shrinker)
         (apk_dest, profile_dest_dir, proguard_config_file) = \
             BuildAppWithShrinker(app, config, shrinker, checkout_dir, out_dir,
-                options)
+                temp_dir, options)
         dex_size = ComputeSizeOfDexFilesInApk(apk_dest)
         result['apk_dest'] = apk_dest,
         result['build_status'] = 'success'
@@ -278,7 +288,7 @@
           }
           (apk_dest, profile_dest_dir, ext_proguard_config_file) = \
               BuildAppWithShrinker(app, config, shrinker, checkout_dir, out_dir,
-                  options, extra_env_vars)
+                  temp_dir, options, extra_env_vars)
           dex_size = ComputeSizeOfDexFilesInApk(apk_dest)
           recompilation_result = {
             'apk_dest': apk_dest,
@@ -305,7 +315,7 @@
                   checkout_dir, 'out', shrinker, 'app-release-{}.apk'.format(i))
               RebuildAppWithShrinker(
                   previous_apk, recompiled_apk_dest, ext_proguard_config_file,
-                  shrinker, min_sdk, compile_sdk)
+                  shrinker, min_sdk, compile_sdk, temp_dir)
               recompilation_result = {
                 'apk_dest': recompiled_apk_dest,
                 'build_status': 'success',
@@ -327,7 +337,8 @@
   return result_per_shrinker
 
 def BuildAppWithShrinker(
-    app, config, shrinker, checkout_dir, out_dir, options, env_vars=None):
+    app, config, shrinker, checkout_dir, out_dir, temp_dir, options,
+    env_vars=None):
   print()
   print('Building {} with {}'.format(app, shrinker))
 
@@ -335,7 +346,7 @@
   if options.disable_tot:
     as_utils.remove_r8_dependency(checkout_dir)
   else:
-    as_utils.add_r8_dependency(checkout_dir, IsMinifiedR8(shrinker))
+    as_utils.add_r8_dependency(checkout_dir, temp_dir, IsMinifiedR8(shrinker))
 
   app_module = config.get('app_module', 'app')
   archives_base_name = config.get('archives_base_name', app_module)
@@ -419,7 +430,7 @@
     apk_dest = os.path.join(out_dir, unsigned_apk_name)
     as_utils.MoveFile(unsigned_apk, apk_dest)
 
-  assert IsBuiltWithR8(apk_dest) == ('r8' in shrinker), (
+  assert IsBuiltWithR8(apk_dest, temp_dir) == ('r8' in shrinker), (
       'Unexpected marker in generated APK for {}'.format(shrinker))
 
   profile_dest_dir = os.path.join(out_dir, 'profile')
@@ -428,13 +439,15 @@
   return (apk_dest, profile_dest_dir, proguard_config_dest)
 
 def RebuildAppWithShrinker(
-    apk, apk_dest, proguard_config_file, shrinker, min_sdk, compile_sdk):
+    apk, apk_dest, proguard_config_file, shrinker, min_sdk, compile_sdk,
+    temp_dir):
   assert 'r8' in shrinker
   assert apk_dest.endswith('.apk')
 
   # Compile given APK with shrinker to temporary zip file.
   android_jar = utils.get_android_jar(compile_sdk)
-  r8_jar = utils.R8LIB_JAR if IsMinifiedR8(shrinker) else utils.R8_JAR
+  r8_jar = os.path.join(
+      temp_dir, 'r8lib.jar' if IsMinifiedR8(shrinker) else 'r8.jar')
   zip_dest = apk_dest[:-4] + '.zip'
 
   # TODO(christofferqa): Entry point should be CompatProguard if the shrinker
@@ -613,32 +626,39 @@
   global SHRINKERS
 
   (options, args) = ParseOptions(argv)
-  assert options.disable_tot or os.path.isfile(utils.R8_JAR), (
-      'Cannot build from ToT without r8.jar')
-  assert options.disable_tot or os.path.isfile(utils.R8LIB_JAR), (
-      'Cannot build from ToT without r8lib.jar')
 
-  if options.disable_tot:
-    # Cannot run r8 lib without adding r8lib.jar as an dependency
-    SHRINKERS = [
-        shrinker for shrinker in SHRINKERS
-        if 'minified' not in shrinker]
+  with utils.TempDir() as temp_dir:
+    if options.disable_tot:
+      # Cannot run r8 lib without adding r8lib.jar as an dependency
+      SHRINKERS = [
+          shrinker for shrinker in SHRINKERS
+          if 'minified' not in shrinker]
+    else:
+      if not options.no_build:
+        gradle.RunGradle(['r8', 'r8lib'])
 
-  if not options.no_build and not options.disable_tot:
-    gradle.RunGradle(['r8', 'r8lib'])
+      assert os.path.isfile(utils.R8_JAR), (
+          'Cannot build from ToT without r8.jar')
+      assert os.path.isfile(utils.R8LIB_JAR), (
+          'Cannot build from ToT without r8lib.jar')
 
-  result_per_shrinker_per_app = {}
+      # Make a copy of r8.jar and r8lib.jar such that they stay the same for
+      # the entire execution of this script.
+      shutil.copyfile(utils.R8_JAR, os.path.join(temp_dir, 'r8.jar'))
+      shutil.copyfile(utils.R8LIB_JAR, os.path.join(temp_dir, 'r8lib.jar'))
 
-  if options.app:
-    result_per_shrinker_per_app[options.app] = GetResultsForApp(
-        options.app, APPS.get(options.app), options)
-  else:
-    for app, config in APPS.iteritems():
-      if not config.get('skip', False):
-        result_per_shrinker_per_app[app] = GetResultsForApp(
-            app, config, options)
+    result_per_shrinker_per_app = {}
 
-  LogResultsForApps(result_per_shrinker_per_app, options)
+    if options.app:
+      result_per_shrinker_per_app[options.app] = GetResultsForApp(
+          options.app, APPS.get(options.app), options, temp_dir)
+    else:
+      for app, config in APPS.iteritems():
+        if not config.get('skip', False):
+          result_per_shrinker_per_app[app] = GetResultsForApp(
+              app, config, options, temp_dir)
+
+    LogResultsForApps(result_per_shrinker_per_app, options)
 
 def success(message):
   CGREEN = '\033[32m'