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
--- 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();