DropBox logging of app & system server crashes.

The crashes are also reported to the event log (and of course the
main logcat, like they always have been).  Ordinary Log.e(t,m,e) isn't dropboxed
but there's a new Log.wtf() which always is.  (Still @pending in this change.)

Add a hook to IPowerManager to crash the system server on demand
(only for apps with REBOOT permission, since it's basically a restart).
This is not exposed in PowerManager, must be invoked directly -- mostly
this is there so "Bad Behavior" in dev tools can do it.
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 676d6d56..7d07604 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -606,7 +606,7 @@
         public int uid;
         
         /**
-         * The tag that was provided when the process crashed.
+         * The activity name associated with the error, if known.  May be null.
          */
         public String tag;
 
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index a0498aa..90f46dd 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -979,13 +979,23 @@
             return true;
         }
 
-        case HANDLE_APPLICATION_ERROR_TRANSACTION: {
+        case HANDLE_APPLICATION_CRASH_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder app = data.readStrongBinder();
+            ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
+            handleApplicationCrash(app, ci);
+            reply.writeNoException();
+            return true;
+        }
+
+        case HANDLE_APPLICATION_WTF_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder app = data.readStrongBinder();
             String tag = data.readString();
             ApplicationErrorReport.CrashInfo ci = new ApplicationErrorReport.CrashInfo(data);
-            handleApplicationError(app, tag, ci);
+            boolean res = handleApplicationWtf(app, tag, ci);
             reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
             return true;
         }
 
@@ -2337,7 +2347,20 @@
         /* this base class version is never called */
         return true;
     }
-    public void handleApplicationError(IBinder app, String tag,
+    public void handleApplicationCrash(IBinder app,
+            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(app);
+        crashInfo.writeToParcel(data, 0);
+        mRemote.transact(HANDLE_APPLICATION_CRASH_TRANSACTION, data, reply, 0);
+        reply.readException();
+        reply.recycle();
+        data.recycle();
+    }
+    public boolean handleApplicationWtf(IBinder app, String tag,
             ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -2346,10 +2369,12 @@
         data.writeStrongBinder(app);
         data.writeString(tag);
         crashInfo.writeToParcel(data, 0);
-        mRemote.transact(HANDLE_APPLICATION_ERROR_TRANSACTION, data, reply, 0);
+        mRemote.transact(HANDLE_APPLICATION_WTF_TRANSACTION, data, reply, 0);
         reply.readException();
+        boolean res = reply.readInt() != 0;
         reply.recycle();
         data.recycle();
+        return res;
     }
 
     public void signalPersistentProcesses(int sig) throws RemoteException {
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index e89b3ad0..a4b692f 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -195,6 +195,7 @@
             StringWriter sw = new StringWriter();
             tr.printStackTrace(new PrintWriter(sw));
             stackTrace = sw.toString();
+            exceptionMessage = tr.getMessage();
 
             // Populate fields with the "root cause" exception
             while (tr.getCause() != null) {
diff --git a/core/java/android/app/IActivityController.aidl b/core/java/android/app/IActivityController.aidl
index 804dd61..c76a517 100644
--- a/core/java/android/app/IActivityController.aidl
+++ b/core/java/android/app/IActivityController.aidl
@@ -44,7 +44,7 @@
      * it immediately.
      */
     boolean appCrashed(String processName, int pid,
-            String tag, String shortMsg, String longMsg,
+            String shortMsg, String longMsg,
             long timeMillis, String stackTrace);
     
     /**
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index c890c4c..ca6bfa7 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -242,8 +242,9 @@
     // Special low-level communication with activity manager.
     public void startRunning(String pkg, String cls, String action,
             String data) throws RemoteException;
-
-    public void handleApplicationError(IBinder app, String tag,
+    public void handleApplicationCrash(IBinder app,
+            ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
+    public boolean handleApplicationWtf(IBinder app, String tag,
             ApplicationErrorReport.CrashInfo crashInfo) throws RemoteException;
     
     /*
@@ -349,7 +350,7 @@
     // Please keep these transaction codes the same -- they are also
     // sent by C++ code.
     int START_RUNNING_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
-    int HANDLE_APPLICATION_ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
+    int HANDLE_APPLICATION_CRASH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+1;
     int START_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+2;
     int UNHANDLED_BACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+3;
     int OPEN_CONTENT_URI_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+4;
@@ -446,4 +447,5 @@
     int KILL_APPLICATION_PROCESS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+98;
     int START_ACTIVITY_INTENT_SENDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+99;
     int OVERRIDE_PENDING_TRANSITION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+100;
+    int HANDLE_APPLICATION_WTF_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+101;
 }
diff --git a/core/java/android/os/FileObserver.java b/core/java/android/os/FileObserver.java
index 38d252e..3457815 100644
--- a/core/java/android/os/FileObserver.java
+++ b/core/java/android/os/FileObserver.java
@@ -103,9 +103,7 @@
             try {
                 observer.onEvent(mask, path);
             } catch (Throwable throwable) {
-                Log.e(LOG_TAG, "Unhandled throwable " + throwable.toString() + 
-                        " (returned by observer " + observer + ")", throwable);
-                RuntimeInit.crash("FileObserver", throwable);
+                Log.wtf(LOG_TAG, "Unhandled exception in FileObserver " + observer, throwable);
             }
         }
     }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 0afc537..23762ca 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -31,6 +31,7 @@
     void preventScreenOn(boolean prevent);
     boolean isScreenOn();
     void reboot(String reason);
+    void crash(String message);
 
     // sets the brightness of the backlights (screen, keyboard, button) 0-255
     void setBacklightBrightness(int brightness);
diff --git a/core/java/android/os/MessageQueue.java b/core/java/android/os/MessageQueue.java
index caf0923..bc653d6 100644
--- a/core/java/android/os/MessageQueue.java
+++ b/core/java/android/os/MessageQueue.java
@@ -115,9 +115,7 @@
                         didIdle = true;
                         keep = ((IdleHandler)idler).queueIdle();
                     } catch (Throwable t) {
-                        Log.e("MessageQueue",
-                              "IdleHandler threw exception", t);
-                        RuntimeInit.crash("MessageQueue", t);
+                        Log.wtf("MessageQueue", "IdleHandler threw exception", t);
                     }
 
                     if (!keep) {
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 293dabc..e4eaf45b 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -326,12 +326,11 @@
         {
             synchronized (mToken) {
                 if (mHeld) {
+                    Log.wtf(TAG, "WakeLock finalized while still held: " + mTag);
                     try {
                         mService.releaseWakeLock(mToken, 0);
                     } catch (RemoteException e) {
                     }
-                    RuntimeInit.crash(TAG, new Exception(
-                                "WakeLock finalized while still held: "+mTag));
                 }
             }
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 947ab19..09651f1 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -3710,6 +3710,11 @@
                 "dropbox:";
 
         /**
+         * Nonzero causes Log.wtf() to crash.
+         */
+        public static final String WTF_IS_FATAL = "wtf_is_fatal";
+
+        /**
          * The length of time in milli-seconds that automatic small adjustments to
          * SystemClock are ignored if NITZ_UPDATE_DIFF is not exceeded.
          */
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index e95d0be..7a959a6 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -81,6 +81,13 @@
      */
     public static final int ASSERT = 7;
 
+    /**
+     * Exception class used to capture a stack trace in {@link #wtf()}.
+     */
+    private static class TerribleFailure extends Exception {
+        TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
+    }
+
     private Log() {
     }
 
@@ -170,24 +177,24 @@
 
     /**
      * Checks to see whether or not a log for the specified tag is loggable at the specified level.
-     * 
+     *
      *  The default level of any tag is set to INFO. This means that any level above and including
      *  INFO will be logged. Before you make any calls to a logging method you should check to see
      *  if your tag should be logged. You can change the default level by setting a system property:
      *      'setprop log.tag.<YOUR_LOG_TAG> <LEVEL>'
-     *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPRESS will 
+     *  Where level is either VERBOSE, DEBUG, INFO, WARN, ERROR, ASSERT, or SUPPRESS. SUPPRESS will
      *  turn off all logging for your tag. You can also create a local.prop file that with the
      *  following in it:
      *      'log.tag.<YOUR_LOG_TAG>=<LEVEL>'
      *  and place that in /data/local.prop.
-     *  
+     *
      * @param tag The tag to check.
      * @param level The level to check.
      * @return Whether or not that this is allowed to be logged.
      * @throws IllegalArgumentException is thrown if the tag.length() > 23.
      */
     public static native boolean isLoggable(String tag, int level);
-        
+
     /*
      * Send a {@link #WARN} log message and log the exception.
      * @param tag Used to identify the source of a log message.  It usually identifies
@@ -220,6 +227,46 @@
     }
 
     /**
+     * What a Terrible Failure: Report a condition that should never happen.
+     * The error will always be logged at level ASSERT with the call stack.
+     * Depending on system configuration, a report may be added to the
+     * {@link android.os.DropBoxManager} and/or the process may be terminated
+     * immediately with an error dialog.
+     * @param tag Used to identify the source of a log message.
+     * @param msg The message you would like logged.
+     * @pending
+     */
+    public static int wtf(String tag, String msg) {
+        return wtf(tag, msg, null);
+    }
+
+    /**
+     * What a Terrible Failure: Report an exception that should never happen.
+     * Similar to {@link #wtf(String, String)}, with an exception to log.
+     * @param tag Used to identify the source of a log message.
+     * @param tr An exception to log.
+     * @pending
+     */
+    public static int wtf(String tag, Throwable tr) {
+        return wtf(tag, tr.getMessage(), tr);
+    }
+
+    /**
+     * What a Terrible Failure: Report an exception that should never happen.
+     * Similar to {@link #wtf(String, Throwable)}, with a message as well.
+     * @param tag Used to identify the source of a log message.
+     * @param msg The message you would like logged.
+     * @param tr An exception to log.  May be null.
+     * @pending
+     */
+    public static int wtf(String tag, String msg, Throwable tr) {
+        tr = new TerribleFailure(msg, tr);
+        int bytes = println(ASSERT, tag, getStackTraceString(tr));
+        RuntimeInit.wtf(tag, tr);
+        return bytes;
+    }
+
+    /**
      * Handy function to get a loggable stack trace from a Throwable
      * @param tr An exception to log
      */