bug 660326 - send java exceptions to crash-stats r=dougt
authorBrad Lassey <blassey@mozilla.com>
Wed, 01 Jun 2011 13:54:53 -0400
changeset 70419 54f7bd940f824ab751d816a0bc1d02fa03510336
parent 70418 75907ce0bcbb84205e00d991fd6b38aa9a7de41a
child 70420 61e6c962123c63b39955112346c6c1010a87af9a
push idunknown
push userunknown
push dateunknown
reviewersdougt
bugs660326
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
bug 660326 - send java exceptions to crash-stats r=dougt
embedding/android/GeckoApp.java
embedding/android/GeckoAppShell.java
other-licenses/android/APKOpen.cpp
widget/src/android/AndroidJNI.cpp
--- a/embedding/android/GeckoApp.java
+++ b/embedding/android/GeckoApp.java
@@ -156,32 +156,52 @@ abstract public class GeckoApp
                         showErrorDialog(getString(R.string.no_space_to_start_error));
                     else
                         showErrorDialog(getString(R.string.error_loading_file));
                     Looper.loop();
                     return;
                 }
 
                 // and then fire us up
-                String env = i.getStringExtra("env0");
-                GeckoAppShell.runGecko(getApplication().getPackageResourcePath(),
-                                       i.getStringExtra("args"),
-                                       i.getDataString());
+                try {
+                    String env = i.getStringExtra("env0");
+                    GeckoAppShell.runGecko(getApplication().getPackageResourcePath(),
+                                           i.getStringExtra("args"),
+                                           i.getDataString());
+                } catch (Exception e) {
+                    Log.e("GeckoApp", "top level exception", e);
+                    StringWriter sw = new StringWriter();
+                    e.printStackTrace(new PrintWriter(sw));
+                    GeckoAppShell.reportJavaCrash(sw.toString());
+                }
             }
         }.start();
         return true;
     }
 
     /** Called when the activity is first created. */
     @Override
     public void onCreate(Bundle savedInstanceState)
     {
         mAppContext = this;
         mMainHandler = new Handler();
 
+        mMainHandler.post(new Runnable() {
+            public void run() {
+                try {
+                    Looper.loop();
+                } catch (Exception e) {
+                    Log.e("GeckoApp", "top level exception", e);
+                    StringWriter sw = new StringWriter();
+                    e.printStackTrace(new PrintWriter(sw));
+                    GeckoAppShell.reportJavaCrash(sw.toString());
+                }
+            }
+        });
+
         SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);
         String localeCode = settings.getString(getPackageName() + ".locale", "");
         if (localeCode != null && localeCode.length() > 0)
             GeckoAppShell.setSelectedLocale(localeCode);
 
         Log.i("GeckoApp", "create");
         super.onCreate(savedInstanceState);
 
--- a/embedding/android/GeckoAppShell.java
+++ b/embedding/android/GeckoAppShell.java
@@ -101,16 +101,17 @@ public class GeckoAppShell
     public static native void setSurfaceView(GeckoSurfaceView sv);
     public static native void putenv(String map);
     public static native void onResume();
     public static native void onLowMemory();
     public static native void callObserver(String observerKey, String topic, String data);
     public static native void removeObserver(String observerKey);
     public static native void loadLibs(String apkName, boolean shouldExtract);
     public static native void onChangeNetworkLinkStatus(String status);
+    public static native void reportJavaCrash(String stack);
 
     // A looper thread, accessed by GeckoAppShell.getHandler
     private static class LooperThread extends Thread {
         public SynchronousQueue<Handler> mHandlerQueue =
             new SynchronousQueue<Handler>();
         
         public void run() {
             Looper.prepare();
--- a/other-licenses/android/APKOpen.cpp
+++ b/other-licenses/android/APKOpen.cpp
@@ -234,16 +234,17 @@ SHELL_WRAPPER0(nativeInit)
 SHELL_WRAPPER1(nativeRun, jstring)
 SHELL_WRAPPER1(notifyGeckoOfEvent, jobject)
 SHELL_WRAPPER1(setSurfaceView, jobject)
 SHELL_WRAPPER0(onResume)
 SHELL_WRAPPER0(onLowMemory)
 SHELL_WRAPPER3(callObserver, jstring, jstring, jstring)
 SHELL_WRAPPER1(removeObserver, jstring)
 SHELL_WRAPPER1(onChangeNetworkLinkStatus, jstring)
+SHELL_WRAPPER1(reportJavaCrash, jstring)
 
 static void * xul_handle = NULL;
 static time_t apk_mtime = 0;
 #ifdef DEBUG
 extern "C" int extractLibs = 1;
 #else
 extern "C" int extractLibs = 0;
 #endif
@@ -683,16 +684,17 @@ loadLibs(const char *apkName)
   GETFUNC(nativeRun);
   GETFUNC(notifyGeckoOfEvent);
   GETFUNC(setSurfaceView);
   GETFUNC(onResume);
   GETFUNC(onLowMemory);
   GETFUNC(callObserver);
   GETFUNC(removeObserver);
   GETFUNC(onChangeNetworkLinkStatus);
+  GETFUNC(reportJavaCrash);
 #undef GETFUNC
   gettimeofday(&t1, 0);
   struct rusage usage2;
   getrusage(RUSAGE_SELF, &usage2);
   __android_log_print(ANDROID_LOG_ERROR, "GeckoLibLoad", "Loaded libs in %dms total, %d faults",
                       (t1.tv_sec - t0.tv_sec)*1000 + (t1.tv_usec - t0.tv_usec)/1000, 
                       usage2.ru_majflt-usage1.ru_majflt);
 }
--- a/widget/src/android/AndroidJNI.cpp
+++ b/widget/src/android/AndroidJNI.cpp
@@ -48,32 +48,34 @@
 #include "nsWindow.h"
 #include <android/log.h>
 #include "nsIObserverService.h"
 #include "mozilla/Services.h"
 #include "nsINetworkLinkService.h"
 
 #ifdef MOZ_CRASHREPORTER
 #include "nsICrashReporter.h"
+#include "nsExceptionHandler.h"
 #endif
 
 
 using namespace mozilla;
 
 /* Forward declare all the JNI methods as extern "C" */
 
 extern "C" {
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_nativeInit(JNIEnv *, jclass);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyGeckoOfEvent(JNIEnv *, jclass, jobject event);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_setSurfaceView(JNIEnv *jenv, jclass, jobject sv);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onResume(JNIEnv *, jclass);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onLowMemory(JNIEnv *, jclass);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_callObserver(JNIEnv *, jclass, jstring observerKey, jstring topic, jstring data);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_removeObserver(JNIEnv *jenv, jclass, jstring jObserverKey);
     NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_onChangeNetworkLinkStatus(JNIEnv *, jclass, jstring status);
+    NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *, jclass, jstring stack);
 }
 
 
 /*
  * Incoming JNI methods
  */
 
 NS_EXPORT void JNICALL
@@ -147,8 +149,17 @@ Java_org_mozilla_gecko_GeckoAppShell_onC
         return;
 
     nsJNIString sStatus(jStatus, jenv);
 
     nsAppShell::gAppShell->NotifyObservers(nsnull,
                                            NS_NETWORK_LINK_TOPIC,
                                            sStatus.get());
 }
+
+NS_EXPORT void JNICALL
+Java_org_mozilla_gecko_GeckoAppShell_reportJavaCrash(JNIEnv *, jclass, jstring stack)
+{
+     nsJNIString javaStack(stack);
+     CrashReporter::AppendAppNotesToCrashReport(
+         NS_ConvertUTF16toUTF8(javaStack));
+    abort();
+}