From 8e917414e05ec32b747abf241f353044af4626e2 Mon Sep 17 00:00:00 2001 From: F43nd1r Date: Fri, 12 Aug 2016 12:53:52 +0200 Subject: [PATCH 1/3] do not kill the process if a debugger is attached, display and log a warning about it. --- .../java/org/acra/builder/ReportExecutor.java | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/acra/builder/ReportExecutor.java b/src/main/java/org/acra/builder/ReportExecutor.java index 88f1f4478d..0dc2e45499 100644 --- a/src/main/java/org/acra/builder/ReportExecutor.java +++ b/src/main/java/org/acra/builder/ReportExecutor.java @@ -7,6 +7,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; +import android.os.Debug; import android.os.Looper; import android.support.annotation.NonNull; import android.support.annotation.Nullable; @@ -145,6 +146,7 @@ public void execute(@NonNull final ReportBuilder reportBuilder) { || (config.resToastText() != 0 && (reportingInteractionMode == ReportingInteractionMode.NOTIFICATION || reportingInteractionMode == ReportingInteractionMode.DIALOG)); final TimeHelper sentToastTimeMillis = new TimeHelper(); + boolean displayingToast = false; if (shouldDisplayToast) { new Thread() { @@ -162,10 +164,25 @@ public void run() { } }.start(); + displayingToast = true; // We will wait a few seconds at the end of the method to be sure // that the Toast can be read by the user. } + if (Debug.isDebuggerConnected()) { + final String warning = "Warning: Acra may behave differently with a debugger attached"; + new Thread() { + @Override + public void run() { + Looper.prepare(); + Toast.makeText(context, warning, Toast.LENGTH_LONG).show(); + sentToastTimeMillis.setInitialTimeMillis(System.currentTimeMillis()); + Looper.loop(); + } + }.start(); + ACRA.log.w(LOG_TAG, warning); + displayingToast = true; + } final CrashReportData crashReportData = crashReportDataFactory.createCrashData(reportBuilder); @@ -195,7 +212,7 @@ public void run() { final boolean showDirectDialog = (reportingInteractionMode == ReportingInteractionMode.DIALOG) && !prefs.getBoolean(ACRA.PREF_ALWAYS_ACCEPT, false); - if (shouldDisplayToast) { + if (displayingToast) { // A toast is being displayed, we have to wait for its end before doing anything else. new Thread() { @@ -277,8 +294,10 @@ public void run() { lastActivityManager.clearLastActivity(); } - android.os.Process.killProcess(android.os.Process.myPid()); - System.exit(10); + if (!Debug.isDebuggerConnected()) { + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(10); + } } } From 0153f59208281e8651343fd6da7c8915b97345ad Mon Sep 17 00:00:00 2001 From: F43nd1r Date: Mon, 15 Aug 2016 17:02:13 +0200 Subject: [PATCH 2/3] remove useless displayingToast, prevent reporting to android framework when debugger is connected --- src/main/java/org/acra/builder/ReportExecutor.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/acra/builder/ReportExecutor.java b/src/main/java/org/acra/builder/ReportExecutor.java index 0dc2e45499..2b69f8a9c9 100644 --- a/src/main/java/org/acra/builder/ReportExecutor.java +++ b/src/main/java/org/acra/builder/ReportExecutor.java @@ -146,7 +146,6 @@ public void execute(@NonNull final ReportBuilder reportBuilder) { || (config.resToastText() != 0 && (reportingInteractionMode == ReportingInteractionMode.NOTIFICATION || reportingInteractionMode == ReportingInteractionMode.DIALOG)); final TimeHelper sentToastTimeMillis = new TimeHelper(); - boolean displayingToast = false; if (shouldDisplayToast) { new Thread() { @@ -164,12 +163,12 @@ public void run() { } }.start(); - displayingToast = true; // We will wait a few seconds at the end of the method to be sure // that the Toast can be read by the user. } - if (Debug.isDebuggerConnected()) { + //we cannot kill the process if a debugger is connected, as this would kill the whole application + if (Debug.isDebuggerConnected() && reportBuilder.isEndApplication()) { final String warning = "Warning: Acra may behave differently with a debugger attached"; new Thread() { @Override @@ -181,7 +180,6 @@ public void run() { } }.start(); ACRA.log.w(LOG_TAG, warning); - displayingToast = true; } final CrashReportData crashReportData = crashReportDataFactory.createCrashData(reportBuilder); @@ -212,7 +210,7 @@ public void run() { final boolean showDirectDialog = (reportingInteractionMode == ReportingInteractionMode.DIALOG) && !prefs.getBoolean(ACRA.PREF_ALWAYS_ACCEPT, false); - if (displayingToast) { + if (shouldDisplayToast) { // A toast is being displayed, we have to wait for its end before doing anything else. new Thread() { @@ -264,7 +262,8 @@ private void endApplication(@Nullable Thread uncaughtExceptionThread, Throwable final boolean letDefaultHandlerEndApplication = config.alsoReportToAndroidFramework(); final boolean handlingUncaughtException = uncaughtExceptionThread != null; - if (handlingUncaughtException && letDefaultHandlerEndApplication && defaultExceptionHandler != null) { + //defaultExceptionHandler kills the application, so don't do this if a debugger is connected + if (!Debug.isDebuggerConnected() && handlingUncaughtException && letDefaultHandlerEndApplication && defaultExceptionHandler != null) { // Let the system default handler do it's job and display the force close dialog. if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Handing Exception on to default ExceptionHandler"); defaultExceptionHandler.uncaughtException(uncaughtExceptionThread, th); @@ -293,7 +292,7 @@ public void run() { } lastActivityManager.clearLastActivity(); } - + //prevent process kill if a debugger is attached, as this would kill the whole application if (!Debug.isDebuggerConnected()) { android.os.Process.killProcess(android.os.Process.myPid()); System.exit(10); From 155bd829cb5d50ee3d845cb899245c3ad9f50b34 Mon Sep 17 00:00:00 2001 From: F43nd1r Date: Mon, 5 Sep 2016 13:16:09 +0200 Subject: [PATCH 3/3] Refactor to remove repeated checks for Debug.isDebuggerConnected --- .../java/org/acra/builder/ReportExecutor.java | 80 ++++++++++--------- 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/src/main/java/org/acra/builder/ReportExecutor.java b/src/main/java/org/acra/builder/ReportExecutor.java index 2b69f8a9c9..170e13780d 100644 --- a/src/main/java/org/acra/builder/ReportExecutor.java +++ b/src/main/java/org/acra/builder/ReportExecutor.java @@ -167,20 +167,6 @@ public void run() { // We will wait a few seconds at the end of the method to be sure // that the Toast can be read by the user. } - //we cannot kill the process if a debugger is connected, as this would kill the whole application - if (Debug.isDebuggerConnected() && reportBuilder.isEndApplication()) { - final String warning = "Warning: Acra may behave differently with a debugger attached"; - new Thread() { - @Override - public void run() { - Looper.prepare(); - Toast.makeText(context, warning, Toast.LENGTH_LONG).show(); - sentToastTimeMillis.setInitialTimeMillis(System.currentTimeMillis()); - Looper.loop(); - } - }.start(); - ACRA.log.w(LOG_TAG, warning); - } final CrashReportData crashReportData = crashReportDataFactory.createCrashData(reportBuilder); @@ -251,7 +237,23 @@ private void dialogAndEnd(@NonNull ReportBuilder reportBuilder, @NonNull File re if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Wait for Toast + worker ended. Kill Application ? " + reportBuilder.isEndApplication()); if (reportBuilder.isEndApplication()) { - endApplication(reportBuilder.getUncaughtExceptionThread(), reportBuilder.getException()); + if(Debug.isDebuggerConnected()){ + //Killing a process with a debugger attached would kill the whole application, so don't do that. + final String warning = "Warning: Acra may behave differently with a debugger attached"; + new Thread() { + @Override + public void run() { + Looper.prepare(); + Toast.makeText(context, warning, Toast.LENGTH_LONG).show(); + Looper.loop(); + } + }.start(); + ACRA.log.w(LOG_TAG, warning); + //do as much cleanup as we can without killing the process + finishLastActivity(reportBuilder.getUncaughtExceptionThread()); + }else { + endApplication(reportBuilder.getUncaughtExceptionThread(), reportBuilder.getException()); + } } } @@ -262,41 +264,41 @@ private void endApplication(@Nullable Thread uncaughtExceptionThread, Throwable final boolean letDefaultHandlerEndApplication = config.alsoReportToAndroidFramework(); final boolean handlingUncaughtException = uncaughtExceptionThread != null; - //defaultExceptionHandler kills the application, so don't do this if a debugger is connected - if (!Debug.isDebuggerConnected() && handlingUncaughtException && letDefaultHandlerEndApplication && defaultExceptionHandler != null) { + if (handlingUncaughtException && letDefaultHandlerEndApplication && defaultExceptionHandler != null) { // Let the system default handler do it's job and display the force close dialog. if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Handing Exception on to default ExceptionHandler"); defaultExceptionHandler.uncaughtException(uncaughtExceptionThread, th); } else { + finishLastActivity(uncaughtExceptionThread); // If ACRA handles user notifications with a Toast or a Notification // the Force Close dialog is one more notification to the user... // We choose to close the process ourselves using the same actions. - // Trying to solve https://github.com/ACRA/acra/issues/42#issuecomment-12134144 - // Determine the current/last Activity that was started and close - // it. Activity#finish (and maybe it's parent too). - final Activity lastActivity = lastActivityManager.getLastActivity(); - if (lastActivity != null) { - if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Finishing the last Activity prior to killing the Process"); - lastActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - lastActivity.finish(); - if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Finished " + lastActivity.getClass()); - } - }); + android.os.Process.killProcess(android.os.Process.myPid()); + System.exit(10); + } + } - // A crashed activity won't continue its lifecycle. So we only wait if something else crashed - if (uncaughtExceptionThread != lastActivity.getMainLooper().getThread()) { - lastActivityManager.waitForActivityStop(100); + private void finishLastActivity(Thread uncaughtExceptionThread){ + // Trying to solve https://github.com/ACRA/acra/issues/42#issuecomment-12134144 + // Determine the current/last Activity that was started and close + // it. Activity#finish (and maybe it's parent too). + final Activity lastActivity = lastActivityManager.getLastActivity(); + if (lastActivity != null) { + if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Finishing the last Activity prior to killing the Process"); + lastActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + lastActivity.finish(); + if (ACRA.DEV_LOGGING) ACRA.log.d(LOG_TAG, "Finished " + lastActivity.getClass()); } - lastActivityManager.clearLastActivity(); - } - //prevent process kill if a debugger is attached, as this would kill the whole application - if (!Debug.isDebuggerConnected()) { - android.os.Process.killProcess(android.os.Process.myPid()); - System.exit(10); + }); + + // A crashed activity won't continue its lifecycle. So we only wait if something else crashed + if (uncaughtExceptionThread != lastActivity.getMainLooper().getThread()) { + lastActivityManager.waitForActivityStop(100); } + lastActivityManager.clearLastActivity(); } }