Add additional check for valid Zip file before multidex install

Bug: 11895788
Change-Id: Id4f6e5b09be809eeb29367bebe78c03e49864cbf
diff --git a/library/src/android/support/multidex/MultiDex.java b/library/src/android/support/multidex/MultiDex.java
index 064c66a..7a99142 100644
--- a/library/src/android/support/multidex/MultiDex.java
+++ b/library/src/android/support/multidex/MultiDex.java
@@ -151,14 +151,18 @@
                 }
 
                 File dexDir = new File(context.getFilesDir(), SECONDARY_FOLDER_NAME);
-                List<File> files = MultiDexExtractor.load(applicationInfo, dexDir);
-                if (!files.isEmpty()) {
-                    if (Build.VERSION.SDK_INT >= 19) {
-                        V19.install(loader, files, dexDir);
-                    } else if (Build.VERSION.SDK_INT >= 14) {
-                        V14.install(loader, files, dexDir);
+                List<File> files = MultiDexExtractor.load(applicationInfo, dexDir, false);
+                if (checkValidZipFiles(files)) {
+                    installSecondaryDexes(loader, dexDir, files);
+                } else {
+                    Log.w(TAG, "Files were not valid zip files.  Forcing a reload.");
+                    // Try again, but this time force a reload of the zip file.
+                    files = MultiDexExtractor.load(applicationInfo, dexDir, true);
+                    if (checkValidZipFiles(files)) {
+                        installSecondaryDexes(loader, dexDir, files);
                     } else {
-                        V4.install(loader, files);
+                        // Second time didn't work, give up
+                        throw new RuntimeException("Zip files were not valid.");
                     }
                 }
             }
@@ -169,6 +173,33 @@
         }
     }
 
+    private static void installSecondaryDexes(ClassLoader loader, File dexDir, List<File> files)
+            throws IllegalArgumentException, IllegalAccessException, NoSuchFieldException,
+            InvocationTargetException, NoSuchMethodException, IOException {
+        if (!files.isEmpty()) {
+            if (Build.VERSION.SDK_INT >= 19) {
+                V19.install(loader, files, dexDir);
+            } else if (Build.VERSION.SDK_INT >= 14) {
+                V14.install(loader, files, dexDir);
+            } else {
+                V4.install(loader, files);
+            }
+        }
+    }
+
+    /**
+     * Returns whether all files in the list are valid zip files.  If {@code files} is empty, then
+     * returns true.
+     */
+    private static boolean checkValidZipFiles(List<File> files) {
+        for (File file : files) {
+            if (!MultiDexExtractor.verifyZipFile(file)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     /**
      * Locates a given field anywhere in the class inheritance hierarchy.
      *
diff --git a/library/src/android/support/multidex/MultiDexExtractor.java b/library/src/android/support/multidex/MultiDexExtractor.java
index e9eec82..66bf75f 100644
--- a/library/src/android/support/multidex/MultiDexExtractor.java
+++ b/library/src/android/support/multidex/MultiDexExtractor.java
@@ -64,9 +64,9 @@
      * @throws IOException if encounters a problem while reading or writing
      *         secondary dex files
      */
-    static List<File> load(ApplicationInfo applicationInfo, File dexDir)
+    static List<File> load(ApplicationInfo applicationInfo, File dexDir, boolean forceReload)
             throws IOException {
-        Log.i(TAG, "load(" + applicationInfo.sourceDir + ")");
+        Log.i(TAG, "load(" + applicationInfo.sourceDir + ", forceReload=" + forceReload + ")");
         File sourceApk = new File(applicationInfo.sourceDir);
         long lastModified = sourceApk.lastModified();
         String extractedFilePrefix = sourceApk.getName()
@@ -87,7 +87,7 @@
                 files.add(extractedFile);
 
                 Log.i(TAG, "Need extracted file " + extractedFile);
-                if (!extractedFile.isFile()) {
+                if (forceReload || !extractedFile.isFile()) {
                     Log.i(TAG, "Extraction is needed for file " + extractedFile);
                     int numAttempts = 0;
                     boolean isExtractionSuccessful = false;
@@ -133,6 +133,10 @@
         return files;
     }
 
+    /**
+     * This removes any old zip and dex files or extraneous files from the secondary-dexes
+     * directory.
+     */
     private static void prepareDexDir(File dexDir, final String extractedFilePrefix,
             final long sourceLastModified) throws IOException {
         dexDir.mkdir();
@@ -146,7 +150,7 @@
             @Override
             public boolean accept(File pathname) {
                 return (!pathname.getName().startsWith(extractedFilePrefix))
-                    || (pathname.lastModified() < sourceLastModified);
+                        || (pathname.lastModified() < sourceLastModified);
             }
         };
         File[] files = dexDir.listFiles(filter);
@@ -209,7 +213,7 @@
     /**
      * Returns whether the file is a valid zip file.
      */
-    private static boolean verifyZipFile(File file) {
+    static boolean verifyZipFile(File file) {
         try {
             ZipFile zipFile = new ZipFile(file);
             try {