Bug 1391268 - 3. Detect corrupt APK when loading libs; r?snorp draft
authorJim Chen <nchen@mozilla.com>
Wed, 31 Jan 2018 15:34:18 -0500
changeset 749617 9e0791e673e47a159b07ddd15062682a5dde8181
parent 749616 20f0a95273efb12bd58c36a11691e0890e53c03a
child 749618 ae0c2ce35aaca45149af26eb2649a79305bde2e3
push id97462
push userbmo:nchen@mozilla.com
push dateWed, 31 Jan 2018 20:35:46 +0000
reviewerssnorp
bugs1391268
milestone60.0a1
Bug 1391268 - 3. Detect corrupt APK when loading libs; r?snorp On the second pass after failing the first time to load libraries, enable CRC verification and detect if the APK is corrupt. In that case, instead of crashing, we send out an event to the application. MozReview-Commit-ID: 4b97Z8EUHZe
mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
--- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
+++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoThread.java
@@ -48,16 +48,18 @@ public class GeckoThread extends Thread 
         // After initializing profile and prefs.
         @WrapForJNI PROFILE_READY(5),
         // After initializing frontend JS
         @WrapForJNI RUNNING(6),
         // After granting request to shutdown
         @WrapForJNI EXITING(3),
         // After granting request to restart
         @WrapForJNI RESTARTING(3),
+        // After failed lib extraction due to corrupted APK
+        CORRUPT_APK(2),
         // After exiting GeckoThread (corresponding to "Gecko:Exited" event)
         @WrapForJNI EXITED(0);
 
         /* The rank is an arbitrary value reflecting the amount of components or features
          * that are available for use. During startup and up to the RUNNING state, the
          * rank value increases because more components are initialized and available for
          * use. During shutdown and up to the EXITED state, the rank value decreases as
          * components are shut down and become unavailable. EXITING has the same rank as
@@ -244,16 +246,17 @@ public class GeckoThread extends Thread 
     public static boolean isRunning() {
         return isState(State.RUNNING);
     }
 
     private static void loadGeckoLibs(final Context context, final String resourcePath) {
         GeckoLoader.loadSQLiteLibs(context, resourcePath);
         GeckoLoader.loadNSSLibs(context, resourcePath);
         GeckoLoader.loadGeckoLibs(context, resourcePath);
+        setState(State.LIBS_READY);
     }
 
     private static void initGeckoEnvironment() {
         final Context context = GeckoAppShell.getApplicationContext();
         GeckoLoader.loadMozGlue(context);
         setState(State.MOZGLUE_READY);
 
         final Locale locale = Locale.getDefault();
@@ -266,29 +269,34 @@ public class GeckoThread extends Thread 
             res.updateConfiguration(config, null);
         }
 
         final String resourcePath = context.getPackageResourcePath();
         GeckoLoader.setupGeckoEnvironment(context, context.getFilesDir().getPath());
 
         try {
             loadGeckoLibs(context, resourcePath);
-
+            return;
         } catch (final Exception e) {
             // Cannot load libs; try clearing the cached files.
             Log.w(LOGTAG, "Clearing cache after load libs exception", e);
-            FileUtils.delTree(GeckoLoader.getCacheDir(context),
-                              new FileUtils.FilenameRegexFilter(".*\\.so(?:\\.crc)?$"),
-                              /* recurse */ true);
-
-            // Then try loading again. If this throws again, we actually crash.
-            loadGeckoLibs(context, resourcePath);
         }
 
-        setState(State.LIBS_READY);
+        FileUtils.delTree(GeckoLoader.getCacheDir(context),
+                          new FileUtils.FilenameRegexFilter(".*\\.so(?:\\.crc)?$"),
+                          /* recurse */ true);
+
+        if (!GeckoLoader.verifyCRC(resourcePath)) {
+            setState(State.CORRUPT_APK);
+            EventDispatcher.getInstance().dispatch("Gecko:CorruptAPK", null);
+            return;
+        }
+
+        // Then try loading again. If this throws again, we actually crash.
+        loadGeckoLibs(context, resourcePath);
     }
 
     private String[] getMainProcessArgs() {
         final Context context = GeckoAppShell.getApplicationContext();
         final ArrayList<String> args = new ArrayList<String>();
 
         // argv[0] is the program name, which for us is the package name.
         args.add(context.getPackageName());
@@ -375,17 +383,17 @@ public class GeckoThread extends Thread 
                     // Preload the content ("tab") child process.
                     GeckoProcessManager.getInstance().preload("tab");
                 }
             });
         }
 
         // Wait until initialization before calling Gecko entry point.
         synchronized (this) {
-            while (!mInitialized) {
+            while (!mInitialized || !isState(State.LIBS_READY)) {
                 try {
                     wait();
                 } catch (final InterruptedException e) {
                 }
             }
         }
 
         final String[] args = isChildProcess() ? mArgs : getMainProcessArgs();