Prepare for "lookup in library classes before program classes"

This reverts commit 7464530e9286ec3b6841208c66eec7bbb2dd54f2, adding
a flag to switch between "lookup in library classes before program
classes" and "lookup in program classes before library classes".

The default is kept as "lookup in program classes before library
classes"

This option for switching is only intended to temporary until
the related definitionFor issues have been resolved, and the
compilation setup for all clients has been fixed.

Bug: 120884788
Change-Id: I861739ffbd18cd5927fd6088a380a24cb8804883
diff --git a/tools/run_on_app.py b/tools/run_on_app.py
index a480214..b8bd0ed 100755
--- a/tools/run_on_app.py
+++ b/tools/run_on_app.py
@@ -15,6 +15,7 @@
 import gmscore_data
 import golem
 import nest_data
+from sanitize_libraries import SanitizeLibraries
 import toolhelper
 import utils
 import youtube_data
@@ -301,9 +302,14 @@
 
   if options.compiler == 'r8':
     if 'pgconf' in values and not options.k:
-      for pgconf in values['pgconf']:
-        args.extend(['--pg-conf', pgconf])
-        app_provided_pg_conf = True
+      sanitized_lib_path = os.path.join(
+          os.path.abspath(outdir), 'sanitized_lib.jar')
+      sanitized_pgconf_path = os.path.join(
+          os.path.abspath(outdir), 'sanitized.config')
+      SanitizeLibraries(
+          sanitized_lib_path, sanitized_pgconf_path, values['pgconf'])
+      args.extend(['--pg-conf', sanitized_pgconf_path])
+      app_provided_pg_conf = True
     if options.k:
       args.extend(['--pg-conf', options.k])
     if 'maindexrules' in values:
diff --git a/tools/sanitize_libraries.py b/tools/sanitize_libraries.py
new file mode 100755
index 0000000..e67a06e
--- /dev/null
+++ b/tools/sanitize_libraries.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+from __future__ import print_function
+import os
+import sys
+import zipfile
+
+# Proguard lookup program classes before library classes. In R8 this is
+# not the behaviour (it used to be) R8 will check library classes before
+# program classes. Some apps have duplicate classes in the library and program.
+# To make these apps work with R8 simulate program classes before library
+# classes by creating a new library jar which have all the provided library
+# classes which are not also in program classes.
+def SanitizeLibraries(sanitized_lib_path, sanitized_pgconf_path, pgconfs):
+
+  injars = []
+  libraryjars = []
+
+  with open(sanitized_pgconf_path, 'w') as sanitized_pgconf:
+    for pgconf in pgconfs:
+      pgconf_dirname = os.path.abspath(os.path.dirname(pgconf))
+      first_library_jar = True
+      with open(pgconf) as pgconf_file:
+        for line in pgconf_file:
+          trimmed = line.strip()
+          if trimmed.startswith('-injars'):
+            # Collect -injars and leave them in the configuration.
+            injar = os.path.join(
+                pgconf_dirname, trimmed[len('-injars'):].strip())
+            injars.append(injar)
+            sanitized_pgconf.write('-injars {}\n'.format(injar))
+          elif trimmed.startswith('-libraryjars'):
+            # Collect -libraryjars and replace them with the sanitized library.
+            libraryjar = os.path.join(
+                pgconf_dirname, trimmed[len('-libraryjars'):].strip())
+            libraryjars.append(libraryjar)
+            if first_library_jar:
+              sanitized_pgconf.write(
+                  '-libraryjars {}\n'.format(sanitized_lib_path))
+              first_library_jar = False
+            sanitized_pgconf.write('# {}'.format(line))
+          else:
+            sanitized_pgconf.write(line)
+
+  program_entries = set()
+  library_entries = set()
+
+  for injar in injars:
+    with zipfile.ZipFile(injar, 'r') as injar_zf:
+      for zipinfo in injar_zf.infolist():
+        program_entries.add(zipinfo.filename)
+
+  with zipfile.ZipFile(sanitized_lib_path, 'w') as output_zf:
+    for libraryjar in libraryjars:
+      with zipfile.ZipFile(libraryjar, 'r') as input_zf:
+       for zipinfo in input_zf.infolist():
+         if (not zipinfo.filename in program_entries
+             and not zipinfo.filename in library_entries):
+           library_entries.add(zipinfo.filename)
+           output_zf.writestr(zipinfo, input_zf.read(zipinfo))
+
+  return sanitized_pgconf_path
+
+def main(argv):
+  if (len(argv) < 3):
+    print("Wrong number of arguments!")
+    print("Usage: sanitize_libraries.py " +
+          "<sanitized_lib> <sanitized_pgconf> (<existing_pgconf)+")
+    return 1
+  else:
+    SanitizeLibraries(argv[0], argv[1], argv[2:])
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/tools/utils.py b/tools/utils.py
index f8c1afe..7931c52 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -339,16 +339,18 @@
   return exit_code == 0
 
 class TempDir(object):
- def __init__(self, prefix=''):
+ def __init__(self, prefix='', delete=True):
    self._temp_dir = None
    self._prefix = prefix
+   self._delete = delete
 
  def __enter__(self):
    self._temp_dir = tempfile.mkdtemp(self._prefix)
    return self._temp_dir
 
  def __exit__(self, *_):
-   shutil.rmtree(self._temp_dir, ignore_errors=True)
+   if self._delete:
+     shutil.rmtree(self._temp_dir, ignore_errors=True)
 
 class ChangedWorkingDirectory(object):
  def __init__(self, working_directory, quiet=False):