diff options
Diffstat (limited to 'services/java/com/android/server/am/ActivityManagerService.java')
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 390 |
1 files changed, 357 insertions, 33 deletions
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index 9471eff..f2959e3 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -30,6 +30,7 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.AlertDialog; +import android.app.ApplicationErrorReport; import android.app.Dialog; import android.app.IActivityWatcher; import android.app.IApplicationThread; @@ -41,6 +42,7 @@ import android.app.IThumbnailReceiver; import android.app.Instrumentation; import android.app.PendingIntent; import android.app.ResultInfo; +import android.content.ActivityNotFoundException; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -78,10 +80,14 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.provider.Checkin; import android.provider.Settings; +import android.server.data.CrashData; +import android.server.data.StackTraceElementData; +import android.server.data.ThrowableData; import android.text.TextUtils; import android.util.Config; import android.util.EventLog; import android.util.Log; +import android.util.LogPrinter; import android.util.PrintWriterPrinter; import android.util.SparseArray; import android.view.Gravity; @@ -92,10 +98,13 @@ import android.view.WindowManagerPolicy; import dalvik.system.Zygote; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.PrintWriter; import java.lang.IllegalStateException; import java.lang.ref.WeakReference; @@ -191,6 +200,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // Maximum number of recent tasks that we can remember. static final int MAX_RECENT_TASKS = 20; + // Amount of time after a call to stopAppSwitches() during which we will + // prevent further untrusted switches from happening. + static final long APP_SWITCH_DELAY_TIME = 5*1000; + // How long until we reset a task when the user returns to it. Currently // 30 minutes. static final long ACTIVITY_INACTIVE_RESET_TIME = 1000*60*30; @@ -328,6 +341,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen final ArrayList mHistory = new ArrayList(); /** + * Description of a request to start a new activity, which has been held + * due to app switches being disabled. + */ + class PendingActivityLaunch { + HistoryRecord r; + HistoryRecord sourceRecord; + Uri[] grantedUriPermissions; + int grantedMode; + boolean onlyIfNeeded; + } + + final ArrayList<PendingActivityLaunch> mPendingActivityLaunches + = new ArrayList<PendingActivityLaunch>(); + + /** * List of all active broadcasts that are to be executed immediately * (without waiting for another broadcast to finish). Currently this only * contains broadcasts to registered receivers, to avoid spinning up @@ -705,6 +733,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int mFactoryTest; /** + * The time at which we will allow normal application switches again, + * after a call to {@link #stopAppSwitches()}. + */ + long mAppSwitchesAllowedTime; + + /** + * This is set to true after the first switch after mAppSwitchesAllowedTime + * is set; any switches after that will clear the time. + */ + boolean mDidAppSwitch; + + /** * Set while we are wanting to sleep, to prevent any * activities from being started/resumed. */ @@ -852,6 +892,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen static final int SERVICE_ERROR_MSG = 18; static final int RESUME_TOP_ACTIVITY_MSG = 19; static final int PROC_START_TIMEOUT_MSG = 20; + static final int DO_PENDING_ACTIVITY_LAUNCHES_MSG = 21; AlertDialog mUidAlert; @@ -910,6 +951,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen d.show(); proc.anrDialog = d; } + + ensureScreenEnabled(); } break; case SHOW_FACTORY_ERROR_MSG: { Dialog d = new FactoryErrorDialog( @@ -1041,6 +1084,11 @@ public final class ActivityManagerService extends ActivityManagerNative implemen processStartTimedOutLocked(app); } } + case DO_PENDING_ACTIVITY_LAUNCHES_MSG: { + synchronized (ActivityManagerService.this) { + doPendingActivityLaunchesLocked(true); + } + } } } }; @@ -1495,6 +1543,18 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return null; } + private final HistoryRecord topRunningNonDelayedActivityLocked(HistoryRecord notTop) { + int i = mHistory.size()-1; + while (i >= 0) { + HistoryRecord r = (HistoryRecord)mHistory.get(i); + if (!r.finishing && !r.delayedResume && r != notTop) { + return r; + } + i--; + } + return null; + } + /** * This is a simplified version of topRunningActivityLocked that provides a number of * optional skip-over modes. It is intended for use with the ActivityWatcher hook only. @@ -2245,6 +2305,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return true; } + next.delayedResume = false; + // If the top activity is the resumed one, nothing to do. if (mResumedActivity == next && next.state == ActivityState.RESUMED) { // Make sure we have executed any pending transitions, since there @@ -2471,7 +2533,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return true; } - private final void startActivityLocked(HistoryRecord r, boolean newTask) { + private final void startActivityLocked(HistoryRecord r, boolean newTask, + boolean doResume) { final int NH = mHistory.size(); int addPos = -1; @@ -2558,7 +2621,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if ((r.intent.getFlags() &Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) { resetTaskIfNeededLocked(r, r); - doShow = topRunningActivityLocked(null) == r; + doShow = topRunningNonDelayedActivityLocked(null) == r; } } if (SHOW_APP_STARTING_ICON && doShow) { @@ -2588,13 +2651,15 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mWindowManager.validateAppTokens(mHistory); } - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } } /** * Perform clear operation as requested by - * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: assuming the top task on the - * stack is the one that the new activity is being launched in, look for + * {@link Intent#FLAG_ACTIVITY_CLEAR_TOP}: search from the top of the + * stack to the given task, then look for * an instance of that activity in the stack and, if found, finish all * activities on top of it and return the instance. * @@ -2602,9 +2667,21 @@ public final class ActivityManagerService extends ActivityManagerNative implemen * @return Returns the old activity that should be continue to be used, * or null if none was found. */ - private final HistoryRecord performClearTopTaskLocked(int taskId, + private final HistoryRecord performClearTaskLocked(int taskId, HistoryRecord newR, boolean doClear) { int i = mHistory.size(); + + // First find the requested task. + while (i > 0) { + i--; + HistoryRecord r = (HistoryRecord)mHistory.get(i); + if (r.task.taskId == taskId) { + i++; + break; + } + } + + // Now clear it. while (i > 0) { i--; HistoryRecord r = (HistoryRecord)mHistory.get(i); @@ -2840,15 +2917,75 @@ public final class ActivityManagerService extends ActivityManagerNative implemen intent, resolvedType, aInfo, mConfiguration, resultRecord, resultWho, requestCode, componentSpecified); - HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) - != 0 ? r : null; - + if (mResumedActivity == null + || mResumedActivity.info.applicationInfo.uid != callingUid) { + if (!checkAppSwitchAllowedLocked(callingPid, callingUid, "Activity start")) { + PendingActivityLaunch pal = new PendingActivityLaunch(); + pal.r = r; + pal.sourceRecord = sourceRecord; + pal.grantedUriPermissions = grantedUriPermissions; + pal.grantedMode = grantedMode; + pal.onlyIfNeeded = onlyIfNeeded; + mPendingActivityLaunches.add(pal); + return START_SWITCHES_CANCELED; + } + } + + if (mDidAppSwitch) { + // This is the second allowed switch since we stopped switches, + // so now just generally allow switches. Use case: user presses + // home (switches disabled, switch to home, mDidAppSwitch now true); + // user taps a home icon (coming from home so allowed, we hit here + // and now allow anyone to switch again). + mAppSwitchesAllowedTime = 0; + } else { + mDidAppSwitch = true; + } + + doPendingActivityLaunchesLocked(false); + + return startActivityUncheckedLocked(r, sourceRecord, + grantedUriPermissions, grantedMode, onlyIfNeeded, true); + } + + private final void doPendingActivityLaunchesLocked(boolean doResume) { + final int N = mPendingActivityLaunches.size(); + if (N <= 0) { + return; + } + for (int i=0; i<N; i++) { + PendingActivityLaunch pal = mPendingActivityLaunches.get(i); + startActivityUncheckedLocked(pal.r, pal.sourceRecord, + pal.grantedUriPermissions, pal.grantedMode, pal.onlyIfNeeded, + doResume && i == (N-1)); + } + mPendingActivityLaunches.clear(); + } + + private final int startActivityUncheckedLocked(HistoryRecord r, + HistoryRecord sourceRecord, Uri[] grantedUriPermissions, + int grantedMode, boolean onlyIfNeeded, boolean doResume) { + final Intent intent = r.intent; + final int callingUid = r.launchedFromUid; + + int launchFlags = intent.getFlags(); + // We'll invoke onUserLeaving before onPause only if the launching // activity did not explicitly state that this is an automated launch. mUserLeaving = (launchFlags&Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0; if (DEBUG_USER_LEAVING) Log.v(TAG, "startActivity() => mUserLeaving=" + mUserLeaving); + // If the caller has asked not to resume at this point, we make note + // of this in the record so that we can skip it when trying to find + // the top running activity. + if (!doResume) { + r.delayedResume = true; + } + + HistoryRecord notTop = (launchFlags&Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) + != 0 ? r : null; + // If the onlyIfNeeded flag is set, then we can do this if the activity // being launched is the same as the one making the call... or, as // a special case, if we do not know the caller then we count the @@ -2856,7 +2993,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen if (onlyIfNeeded) { HistoryRecord checkedCaller = sourceRecord; if (checkedCaller == null) { - checkedCaller = topRunningActivityLocked(notTop); + checkedCaller = topRunningNonDelayedActivityLocked(notTop); } if (!checkedCaller.realActivity.equals(r.realActivity)) { // Caller is not the same as launcher, so always needed. @@ -2894,7 +3031,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen launchFlags |= Intent.FLAG_ACTIVITY_NEW_TASK; } - if (resultRecord != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { + if (r.resultTo != null && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // For whatever reason this activity is being launched into a new // task... yet the caller has requested a result back. Well, that // is pretty messed up, so instead immediately send back a cancel @@ -2902,10 +3039,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // dependency on its originator. Log.w(TAG, "Activity is launching as a new task, so cancelling activity result."); sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, + r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); r.resultTo = null; - resultRecord = null; } boolean addingToTask = false; @@ -2916,7 +3052,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If bring to front is requested, and no result is requested, and // we can find a task that was started with this same // component, then instead of launching bring that one to the front. - if (resultRecord == null) { + if (r.resultTo == null) { // See if there is a task to bring to the front. If this is // a SINGLE_INSTANCE activity, there can be one and only one // instance of it in the history, and it is always in its own @@ -2938,7 +3074,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // to have the same behavior as if a new instance was // being started, which means not bringing it to the front // if the caller is not itself in the front. - HistoryRecord curTop = topRunningActivityLocked(notTop); + HistoryRecord curTop = topRunningNonDelayedActivityLocked(notTop); if (curTop.task != taskTop.task) { r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT); boolean callerAtFront = sourceRecord == null @@ -2959,7 +3095,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // the client said not to do anything if that // is the case, so this is it! And for paranoia, make // sure we have correctly resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_RETURN_INTENT_TO_CALLER; } if ((launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0 @@ -2969,7 +3107,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // from the task up to the one being started. In most // cases this means we are resetting the task to its // initial state. - HistoryRecord top = performClearTopTaskLocked( + HistoryRecord top = performClearTaskLocked( taskTop.task.taskId, r, true); if (top != null) { if (top.frontOfTask) { @@ -3035,7 +3173,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // We didn't do anything... but it was needed (a.k.a., client // don't use that intent!) And for paranoia, make // sure we have correctly resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_TASK_TO_FRONT; } } @@ -3052,8 +3192,8 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // If the activity being launched is the same as the one currently // at the top, then we need to check if it should only be launched // once. - HistoryRecord top = topRunningActivityLocked(notTop); - if (top != null && resultRecord == null) { + HistoryRecord top = topRunningNonDelayedActivityLocked(notTop); + if (top != null && r.resultTo == null) { if (top.realActivity.equals(r.realActivity)) { if (top.app != null && top.app.thread != null) { if ((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 @@ -3062,7 +3202,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen logStartActivity(LOG_AM_NEW_INTENT, top, top.task); // For paranoia, make sure we have correctly // resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } if (onlyIfNeeded) { // We don't need to start a new activity, and // the client said not to do anything if that @@ -3077,9 +3219,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } else { - if (resultRecord != null) { + if (r.resultTo != null) { sendActivityResultLocked(-1, - resultRecord, resultWho, requestCode, + r.resultTo, r.resultWho, r.requestCode, Activity.RESULT_CANCELED, null); } return START_CLASS_NOT_FOUND; @@ -3088,7 +3230,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen boolean newTask = false; // Should this be considered a new task? - if (resultRecord == null && !addingToTask + if (r.resultTo == null && !addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_NEW_TASK) != 0) { // todo: should do better management of integers. mCurTask++; @@ -3108,14 +3250,16 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // In this case, we are adding the activity to an existing // task, but the caller has asked to clear that task if the // activity is already running. - HistoryRecord top = performClearTopTaskLocked( + HistoryRecord top = performClearTaskLocked( sourceRecord.task.taskId, r, true); if (top != null) { logStartActivity(LOG_AM_NEW_INTENT, r, top.task); deliverNewIntentLocked(top, r.intent); // For paranoia, make sure we have correctly // resumed the top activity. - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_DELIVERED_TO_TOP; } } else if (!addingToTask && @@ -3128,7 +3272,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen HistoryRecord top = moveActivityToFrontLocked(where); logStartActivity(LOG_AM_NEW_INTENT, r, top.task); deliverNewIntentLocked(top, r.intent); - resumeTopActivityLocked(null); + if (doResume) { + resumeTopActivityLocked(null); + } return START_DELIVERED_TO_TOP; } } @@ -3157,7 +3303,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen EventLog.writeEvent(LOG_AM_CREATE_TASK, r.task.taskId); } logStartActivity(LOG_AM_CREATE_ACTIVITY, r, r.task); - startActivityLocked(r, newTask); + startActivityLocked(r, newTask, doResume); return START_SUCCESS; } @@ -4911,6 +5057,20 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + final void ensureScreenEnabled() { + boolean enableScreen; + synchronized (this) { + enableScreen = !mBooted; + mBooted = true; + } + + if (enableScreen) { + EventLog.writeEvent(LOG_BOOT_PROGRESS_ENABLE_SCREEN, + SystemClock.uptimeMillis()); + enableScreenAfterBoot(); + } + } + public final void activityPaused(IBinder token, Bundle icicle) { // Refuse possible leaked file descriptors if (icicle != null && icicle.hasFileDescriptors()) { @@ -6251,6 +6411,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "moveTaskToFront()"); synchronized(this) { + if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), + Binder.getCallingUid(), "Task to front")) { + return; + } final long origId = Binder.clearCallingIdentity(); try { int N = mRecentTasks.size(); @@ -6335,6 +6499,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "moveTaskToBack()"); synchronized(this) { + if (mResumedActivity != null && mResumedActivity.task.taskId == task) { + if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), + Binder.getCallingUid(), "Task to back")) { + return; + } + } final long origId = Binder.clearCallingIdentity(); moveTaskToBackLocked(task); Binder.restoreCallingIdentity(origId); @@ -6438,6 +6608,10 @@ public final class ActivityManagerService extends ActivityManagerNative implemen "moveTaskBackwards()"); synchronized(this) { + if (!checkAppSwitchAllowedLocked(Binder.getCallingPid(), + Binder.getCallingUid(), "Task backwards")) { + return; + } final long origId = Binder.clearCallingIdentity(); moveTaskBackwardsLocked(task); Binder.restoreCallingIdentity(origId); @@ -7179,6 +7353,55 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } + public void stopAppSwitches() { + if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.STOP_APP_SWITCHES); + } + + synchronized(this) { + mAppSwitchesAllowedTime = SystemClock.uptimeMillis() + + APP_SWITCH_DELAY_TIME; + mDidAppSwitch = false; + mHandler.removeMessages(DO_PENDING_ACTIVITY_LAUNCHES_MSG); + Message msg = mHandler.obtainMessage(DO_PENDING_ACTIVITY_LAUNCHES_MSG); + mHandler.sendMessageDelayed(msg, APP_SWITCH_DELAY_TIME); + } + } + + public void resumeAppSwitches() { + if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES) + != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("Requires permission " + + android.Manifest.permission.STOP_APP_SWITCHES); + } + + synchronized(this) { + // Note that we don't execute any pending app switches... we will + // let those wait until either the timeout, or the next start + // activity request. + mAppSwitchesAllowedTime = 0; + } + } + + boolean checkAppSwitchAllowedLocked(int callingPid, int callingUid, + String name) { + if (mAppSwitchesAllowedTime < SystemClock.uptimeMillis()) { + return true; + } + + final int perm = checkComponentPermission( + android.Manifest.permission.STOP_APP_SWITCHES, callingPid, + callingUid, -1); + if (perm == PackageManager.PERMISSION_GRANTED) { + return true; + } + + Log.w(TAG, name + " request from " + callingUid + " stopped"); + return false; + } + public void setDebugApp(String packageName, boolean waitForDebugger, boolean persistent) { enforceCallingPermission(android.Manifest.permission.SET_DEBUG_APP, @@ -7595,6 +7818,30 @@ public final class ActivityManagerService extends ActivityManagerNative implemen return handleAppCrashLocked(app); } + private ComponentName getErrorReportReceiver(ProcessRecord app) { + IPackageManager pm = ActivityThread.getPackageManager(); + try { + // was an installer package name specified when this app was + // installed? + String installerPackageName = pm.getInstallerPackageName(app.info.packageName); + if (installerPackageName == null) { + return null; + } + + // is there an Activity in this package that handles ACTION_APP_ERROR? + Intent intent = new Intent(Intent.ACTION_APP_ERROR); + ResolveInfo info = pm.resolveIntentForPackage(intent, null, 0, installerPackageName); + if (info == null || info.activityInfo == null) { + return null; + } + + return new ComponentName(installerPackageName, info.activityInfo.name); + } catch (RemoteException e) { + // will return null and no error report will be delivered + } + return null; + } + void makeAppNotRespondingLocked(ProcessRecord app, String tag, String shortMsg, String longMsg, byte[] crashData) { app.notResponding = true; @@ -7713,6 +7960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } void startAppProblemLocked(ProcessRecord app) { + app.errorReportReceiver = getErrorReportReceiver(app); skipCurrentReceiverLocked(app); } @@ -7745,7 +7993,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen public int handleApplicationError(IBinder app, int flags, String tag, String shortMsg, String longMsg, byte[] crashData) { AppErrorResult result = new AppErrorResult(); - ProcessRecord r = null; synchronized (this) { if (app != null) { @@ -7834,16 +8081,96 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int res = result.get(); + Intent appErrorIntent = null; synchronized (this) { if (r != null) { mProcessCrashTimes.put(r.info.processName, r.info.uid, SystemClock.uptimeMillis()); } + if (res == AppErrorDialog.FORCE_QUIT_AND_REPORT) { + appErrorIntent = createAppErrorIntentLocked(r); + res = AppErrorDialog.FORCE_QUIT; + } + } + + if (appErrorIntent != null) { + try { + mContext.startActivity(appErrorIntent); + } catch (ActivityNotFoundException e) { + Log.w(TAG, "bug report receiver dissappeared", e); + } } return res; } + Intent createAppErrorIntentLocked(ProcessRecord r) { + ApplicationErrorReport report = createAppErrorReportLocked(r); + if (report == null) { + return null; + } + Intent result = new Intent(Intent.ACTION_APP_ERROR); + result.setComponent(r.errorReportReceiver); + result.putExtra(Intent.EXTRA_BUG_REPORT, report); + result.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return result; + } + + ApplicationErrorReport createAppErrorReportLocked(ProcessRecord r) { + if (r.errorReportReceiver == null) { + return null; + } + + if (!r.crashing && !r.notResponding) { + return null; + } + + try { + ApplicationErrorReport report = new ApplicationErrorReport(); + report.packageName = r.info.packageName; + report.installerPackageName = r.errorReportReceiver.getPackageName(); + report.processName = r.processName; + + if (r.crashing) { + report.type = ApplicationErrorReport.TYPE_CRASH; + report.crashInfo = new ApplicationErrorReport.CrashInfo(); + + ByteArrayInputStream byteStream = new ByteArrayInputStream( + r.crashingReport.crashData); + DataInputStream dataStream = new DataInputStream(byteStream); + CrashData crashData = new CrashData(dataStream); + ThrowableData throwData = crashData.getThrowableData(); + + report.time = crashData.getTime(); + report.crashInfo.stackTrace = throwData.toString(); + + // extract the source of the exception, useful for report + // clustering + while (throwData.getCause() != null) { + throwData = throwData.getCause(); + } + StackTraceElementData trace = throwData.getStackTrace()[0]; + report.crashInfo.exceptionClassName = throwData.getType(); + report.crashInfo.throwFileName = trace.getFileName(); + report.crashInfo.throwClassName = trace.getClassName(); + report.crashInfo.throwMethodName = trace.getMethodName(); + } else if (r.notResponding) { + report.type = ApplicationErrorReport.TYPE_ANR; + report.anrInfo = new ApplicationErrorReport.AnrInfo(); + + report.anrInfo.activity = r.notRespondingReport.tag; + report.anrInfo.cause = r.notRespondingReport.shortMsg; + report.anrInfo.info = r.notRespondingReport.longMsg; + } + + return report; + } catch (IOException e) { + // we don't send it + } + + return null; + } + public List<ActivityManager.ProcessErrorStateInfo> getProcessesInErrorState() { // assume our apps are happy - lazy create the list List<ActivityManager.ProcessErrorStateInfo> errList = null; @@ -10176,8 +10503,6 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } - final ContentResolver resolver = mContext.getContentResolver(); - // Figure out who all will receive this broadcast. List receivers = null; List<BroadcastFilter> registeredReceivers = null; @@ -10200,8 +10525,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen ActivityThread.getPackageManager().queryIntentReceivers( intent, resolvedType, STOCK_PM_FLAGS); } - registeredReceivers = mReceiverResolver.queryIntent(resolver, - intent, resolvedType, false); + registeredReceivers = mReceiverResolver.queryIntent(intent, resolvedType, false); } } catch (RemoteException ex) { // pm is in same process, this will never happen. |