Merge change 4411 into donut

* changes:
  Squashed commit of the following:
diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java
index 0c8f95d..6b17236 100644
--- a/core/java/android/app/ApplicationErrorReport.java
+++ b/core/java/android/app/ApplicationErrorReport.java
@@ -151,6 +151,11 @@
         public String exceptionClassName;
 
         /**
+         * Message stored in the exception.
+         */
+        public String exceptionMessage;
+
+        /**
          * File which the exception was thrown from.
          */
         public String throwFileName;
@@ -181,6 +186,7 @@
          */
         public CrashInfo(Parcel in) {
             exceptionClassName = in.readString();
+            exceptionMessage = in.readString();
             throwFileName = in.readString();
             throwClassName = in.readString();
             throwMethodName = in.readString();
@@ -192,6 +198,7 @@
          */
         public void writeToParcel(Parcel dest, int flags) {
             dest.writeString(exceptionClassName);
+            dest.writeString(exceptionMessage);
             dest.writeString(throwFileName);
             dest.writeString(throwClassName);
             dest.writeString(throwMethodName);
@@ -203,6 +210,7 @@
          */
         public void dump(Printer pw, String prefix) {
             pw.println(prefix + "exceptionClassName: " + exceptionClassName);
+            pw.println(prefix + "exceptionMessage: " + exceptionMessage);
             pw.println(prefix + "throwFileName: " + throwFileName);
             pw.println(prefix + "throwClassName: " + throwClassName);
             pw.println(prefix + "throwMethodName: " + throwMethodName);
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index ae867fb..755f9c8 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -8218,12 +8218,19 @@
                 report.time = crashData.getTime();
                 report.crashInfo.stackTrace = throwData.toString();
 
-                // extract the source of the exception, useful for report
-                // clustering
+                // Extract the source of the exception, useful for report
+                // clustering. Also extract the "deepest" non-null exception
+                // message.
+                String exceptionMessage = throwData.getMessage();
                 while (throwData.getCause() != null) {
                     throwData = throwData.getCause();
+                    String msg = throwData.getMessage();
+                    if (msg != null && msg.length() > 0) {
+                       exceptionMessage = msg;
+                    }
                 }
                 StackTraceElementData trace = throwData.getStackTrace()[0];
+                report.crashInfo.exceptionMessage = exceptionMessage;
                 report.crashInfo.exceptionClassName = throwData.getType();
                 report.crashInfo.throwFileName = trace.getFileName();
                 report.crashInfo.throwClassName = trace.getClassName();
diff --git a/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java
new file mode 100644
index 0000000..273943f
--- /dev/null
+++ b/tests/permission/src/com/android/framework/permission/tests/SmsManagerPermissionTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.framework.permission.tests;
+
+import java.util.ArrayList;
+
+import android.telephony.SmsManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Verify that SmsManager apis cannot be called without required permissions.
+ */
+public class SmsManagerPermissionTest extends AndroidTestCase {
+
+    private static final String MSG_CONTENTS = "hi";
+    private static final short DEST_PORT = (short)1004;
+    private static final String DEST_NUMBER = "4567";
+    private static final String SRC_NUMBER = "1234";
+
+    /**
+     * Verify that SmsManager.sendTextMessage requires permissions.
+     * <p>Tests Permission:
+     *   {@link android.Manifest.permission#SEND_SMS}.
+     */
+    @SmallTest
+    public void testSendTextMessage() {
+        try {
+            SmsManager.getDefault().sendTextMessage(SRC_NUMBER, DEST_NUMBER, MSG_CONTENTS, null,
+                    null);
+            fail("SmsManager.sendTextMessage did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that SmsManager.sendDataMessage requires permissions.
+     * <p>Tests Permission:
+     *   {@link android.Manifest.permission#SEND_SMS}.
+     */
+    @SmallTest
+    public void testSendDataMessage() {
+        try {
+            SmsManager.getDefault().sendDataMessage(SRC_NUMBER, DEST_NUMBER, DEST_PORT,
+                    MSG_CONTENTS.getBytes(), null, null);
+            fail("SmsManager.sendDataMessage did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    /**
+     * Verify that SmsManager.sendMultipartMessage requires permissions.
+     * <p>Tests Permission:
+     *   {@link android.Manifest.permission#SEND_MMS}.
+     */
+    @SmallTest
+    public void testSendMultipartMessage() {
+        try {
+            ArrayList<String> msgParts = new ArrayList<String>(2);
+            msgParts.add(MSG_CONTENTS);
+            msgParts.add("foo");
+            SmsManager.getDefault().sendMultipartTextMessage(SRC_NUMBER, DEST_NUMBER, msgParts,
+                    null, null);
+            fail("SmsManager.sendMultipartTextMessage did not throw SecurityException as expected");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+}