Home | History | Annotate | Download | only in apprtc
      1 /*
      2  * libjingle
      3  * Copyright 2013, Google Inc.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions are met:
      7  *
      8  *  1. Redistributions of source code must retain the above copyright notice,
      9  *     this list of conditions and the following disclaimer.
     10  *  2. Redistributions in binary form must reproduce the above copyright notice,
     11  *     this list of conditions and the following disclaimer in the documentation
     12  *     and/or other materials provided with the distribution.
     13  *  3. The name of the author may not be used to endorse or promote products
     14  *     derived from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
     19  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     20  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     22  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     23  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
     25  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 package org.appspot.apprtc;
     29 
     30 import android.app.Activity;
     31 import android.app.AlertDialog;
     32 import android.content.DialogInterface;
     33 import android.util.Log;
     34 import android.util.TypedValue;
     35 import android.widget.ScrollView;
     36 import android.widget.TextView;
     37 
     38 import java.io.PrintWriter;
     39 import java.io.StringWriter;
     40 
     41 /**
     42  * Singleton helper: install a default unhandled exception handler which shows
     43  * an informative dialog and kills the app.  Useful for apps whose
     44  * error-handling consists of throwing RuntimeExceptions.
     45  * NOTE: almost always more useful to
     46  * Thread.setDefaultUncaughtExceptionHandler() rather than
     47  * Thread.setUncaughtExceptionHandler(), to apply to background threads as well.
     48  */
     49 public class UnhandledExceptionHandler
     50     implements Thread.UncaughtExceptionHandler {
     51   private static final String TAG = "AppRTCDemoActivity";
     52   private final Activity activity;
     53 
     54   public UnhandledExceptionHandler(final Activity activity) {
     55     this.activity = activity;
     56   }
     57 
     58   public void uncaughtException(Thread unusedThread, final Throwable e) {
     59     activity.runOnUiThread(new Runnable() {
     60         @Override public void run() {
     61           String title = "Fatal error: " + getTopLevelCauseMessage(e);
     62           String msg = getRecursiveStackTrace(e);
     63           TextView errorView = new TextView(activity);
     64           errorView.setText(msg);
     65           errorView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 8);
     66           ScrollView scrollingContainer = new ScrollView(activity);
     67           scrollingContainer.addView(errorView);
     68           Log.e(TAG, title + "\n\n" + msg);
     69           DialogInterface.OnClickListener listener =
     70               new DialogInterface.OnClickListener() {
     71                 @Override public void onClick(
     72                     DialogInterface dialog, int which) {
     73                   dialog.dismiss();
     74                   System.exit(1);
     75                 }
     76               };
     77           AlertDialog.Builder builder =
     78               new AlertDialog.Builder(activity);
     79           builder
     80               .setTitle(title)
     81               .setView(scrollingContainer)
     82               .setPositiveButton("Exit", listener).show();
     83         }
     84       });
     85   }
     86 
     87   // Returns the Message attached to the original Cause of |t|.
     88   private static String getTopLevelCauseMessage(Throwable t) {
     89     Throwable topLevelCause = t;
     90     while (topLevelCause.getCause() != null) {
     91       topLevelCause = topLevelCause.getCause();
     92     }
     93     return topLevelCause.getMessage();
     94   }
     95 
     96   // Returns a human-readable String of the stacktrace in |t|, recursively
     97   // through all Causes that led to |t|.
     98   private static String getRecursiveStackTrace(Throwable t) {
     99     StringWriter writer = new StringWriter();
    100     t.printStackTrace(new PrintWriter(writer));
    101     return writer.toString();
    102   }
    103 }
    104