Snap for 4535700 from 45e52b5ab37a26149ce031caa44bb167da217667 to pi-release

Change-Id: Iabe0625a36e352c7df9ee77952a9071fb0d18a2d
diff --git a/lib/proguard.jar b/lib/proguard.jar
index f7b091e..76717e2 100644
--- a/lib/proguard.jar
+++ b/lib/proguard.jar
Binary files differ
diff --git a/lib/proguardgui.jar b/lib/proguardgui.jar
index adbadc5..732d852 100644
--- a/lib/proguardgui.jar
+++ b/lib/proguardgui.jar
Binary files differ
diff --git a/lib/retrace.jar b/lib/retrace.jar
index 0d8164b..ae50685 100644
--- a/lib/retrace.jar
+++ b/lib/retrace.jar
Binary files differ
diff --git a/src/proguard/Configuration.java b/src/proguard/Configuration.java
index 0b855a5..fc212f6 100644
--- a/src/proguard/Configuration.java
+++ b/src/proguard/Configuration.java
@@ -39,6 +39,24 @@
     // Input and output options.
     ///////////////////////////////////////////////////////////////////////////
 
+    // Android-added: Add -systemjars option.
+    /**
+     * A list of system entries (jars, wars, ears, zips, and directories).
+     *
+     * <p>A system jar is one that appears on the runtime classpath before the program jars. Unless
+     * there are duplicate classes between it and a program jar then it behaves no different to a
+     * library jar. If there are duplicate classes between it and a program jar then the class in
+     * the system jar will be used and the duplicate class in the program jar will be ignored.
+     * Conversely, if a library jar contains duplicates of classes in a program jar then the class
+     * in the program jar will be used and the one in the library jar will be ignored.
+     *
+     * <p>e.g. the android.jar from the Android SDK should usually be treated as a system jar
+     * because at runtime if the APK contains duplicates of classes in android.jar then the ones in
+     * the APK will be ignored; unless the APK does some ClassLoader manipulation to change that
+     * behavior.
+     */
+    public ClassPath systemJars;
+
     /**
      * A list of input and output entries (jars, wars, ears, zips, and directories).
      */
diff --git a/src/proguard/ConfigurationChecker.java b/src/proguard/ConfigurationChecker.java
index 84d4663..05087f5 100644
--- a/src/proguard/ConfigurationChecker.java
+++ b/src/proguard/ConfigurationChecker.java
@@ -50,6 +50,8 @@
     {
         ClassPath programJars = configuration.programJars;
         ClassPath libraryJars = configuration.libraryJars;
+        // Android-added: Get the systemJars list to check.
+        ClassPath systemJars = configuration.systemJars;
 
         // Check that the input isn't empty.
         if (programJars == null)
@@ -79,9 +81,18 @@
         }
 
         // Check for conflicts between input/output entries of the class paths.
+        ClassPath systemAndLibraryJars = new ClassPath();
+        // Android-added: Merge the system and library jars into one list.
+        if (libraryJars != null) {
+            systemAndLibraryJars.addAll(libraryJars);
+        }
+        if (systemJars != null) {
+            systemAndLibraryJars.addAll(systemJars);
+        }
         checkConflicts(programJars, programJars);
-        checkConflicts(programJars, libraryJars);
-        checkConflicts(libraryJars, libraryJars);
+        // Android-changed: Check for conflicts with the system/library jars.
+        checkConflicts(programJars, systemAndLibraryJars);
+        checkConflicts(systemAndLibraryJars, systemAndLibraryJars);
 
         // Print out some general notes if necessary.
         if ((configuration.note == null ||
diff --git a/src/proguard/ConfigurationConstants.java b/src/proguard/ConfigurationConstants.java
index a67eee3..379e80f 100644
--- a/src/proguard/ConfigurationConstants.java
+++ b/src/proguard/ConfigurationConstants.java
@@ -35,6 +35,8 @@
     public static final String INJARS_OPTION       = "-injars";
     public static final String OUTJARS_OPTION      = "-outjars";
     public static final String LIBRARYJARS_OPTION  = "-libraryjars";
+    // Android-added: Add -systemjars option.
+    public static final String SYSTEMJARS_OPTION   = "-systemjars";
     public static final String RESOURCEJARS_OPTION = "-resourcejars";
 
     public static final String KEEP_OPTION                           = "-keep";
diff --git a/src/proguard/ConfigurationParser.java b/src/proguard/ConfigurationParser.java
index 72949cf..b07ef93 100644
--- a/src/proguard/ConfigurationParser.java
+++ b/src/proguard/ConfigurationParser.java
@@ -154,6 +154,8 @@
             else if (ConfigurationConstants.INJARS_OPTION                                    .startsWith(nextWord)) configuration.programJars                      = parseClassPathArgument(configuration.programJars, false);
             else if (ConfigurationConstants.OUTJARS_OPTION                                   .startsWith(nextWord)) configuration.programJars                      = parseClassPathArgument(configuration.programJars, true);
             else if (ConfigurationConstants.LIBRARYJARS_OPTION                               .startsWith(nextWord)) configuration.libraryJars                      = parseClassPathArgument(configuration.libraryJars, false);
+            // Android-added: Parse -systemjars option.
+            else if (ConfigurationConstants.SYSTEMJARS_OPTION                                .startsWith(nextWord)) configuration.systemJars                       = parseClassPathArgument(configuration.systemJars, false);
             else if (ConfigurationConstants.RESOURCEJARS_OPTION                              .startsWith(nextWord)) throw new ParseException("The '-resourcejars' option is no longer supported. Please use the '-injars' option for all input");
             else if (ConfigurationConstants.SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION           .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses      = parseNoArgument(true);
             else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION      .startsWith(nextWord)) configuration.skipNonPublicLibraryClasses      = parseNoArgument(false);
diff --git a/src/proguard/ConfigurationWriter.java b/src/proguard/ConfigurationWriter.java
index d87f47e..c421345 100644
--- a/src/proguard/ConfigurationWriter.java
+++ b/src/proguard/ConfigurationWriter.java
@@ -104,6 +104,13 @@
                         configuration.libraryJars);
         writer.println();
 
+        // Android-added: Write value of -systemjars option to configuration file.
+        // Write the system class path (output entries only).
+        writeJarOptions(ConfigurationConstants.SYSTEMJARS_OPTION,
+                        ConfigurationConstants.SYSTEMJARS_OPTION,
+                        configuration.systemJars);
+        writer.println();
+
         // Write the other options.
         writeOption(ConfigurationConstants.SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION,            configuration.skipNonPublicLibraryClasses);
         writeOption(ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION, !configuration.skipNonPublicLibraryClassMembers);
diff --git a/src/proguard/InputReader.java b/src/proguard/InputReader.java
index 503ce7e..488b6ff 100644
--- a/src/proguard/InputReader.java
+++ b/src/proguard/InputReader.java
@@ -59,6 +59,28 @@
 
         DuplicateClassPrinter duplicateClassPrinter = new DuplicateClassPrinter(notePrinter);
 
+        // Android-added: Read the classes from the systemjars.
+        // These are read into the library ClassPool before the programjars so that any duplicates
+        // between these are programjars will result in the classes in the programjars being
+        // ignored.
+        // Read the system class files, if any.
+        if (configuration.systemJars != null)
+        {
+            // Prepare a data entry reader to filter all classes,
+            // which are then decoded to classes by a class reader,
+            // which are then filtered by removing any that already exist in the libraryClassPool.
+            // which are then put in the class pool by a class pool filler.
+            readInput("Reading system ",
+                      configuration.systemJars,
+                      new ClassFilter(
+                      new ClassReader(true /* isLibrary */,
+                                      configuration.skipNonPublicLibraryClasses,
+                                      configuration.skipNonPublicLibraryClassMembers,
+                                      warningPrinter,
+                      new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter,
+                      new ClassPoolFiller(libraryClassPool)))));
+        }
+
         // Read the program class files.
         // Prepare a data entry reader to filter all classes,
         // which are then decoded to classes by a class reader,
@@ -71,7 +93,9 @@
                                   configuration.skipNonPublicLibraryClassMembers,
                                   warningPrinter,
                   new ClassPresenceFilter(programClassPool, duplicateClassPrinter,
-                  new ClassPoolFiller(programClassPool)))));
+                  // Android-changed: Filter out classes already read from systemjars.
+                  new ClassPresenceFilter(libraryClassPool, duplicateClassPrinter,
+                  new ClassPoolFiller(programClassPool))))));
 
         // Check if we have at least some input classes.
         if (programClassPool.size() == 0)
diff --git a/src/proguard/gradle/ProGuardTask.java b/src/proguard/gradle/ProGuardTask.java
index 447c630..bd9eef6 100644
--- a/src/proguard/gradle/ProGuardTask.java
+++ b/src/proguard/gradle/ProGuardTask.java
@@ -31,7 +31,11 @@
 import proguard.util.ListUtil;
 
 import java.io.*;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
 
 /**
  * This Task allows to configure and run ProGuard from Gradle.