Merge pull request #4464 from ByteHamster/swallow-undeliverable-exception

Swallow undeliverable RxJava exceptions
This commit is contained in:
H. Lehmann 2020-09-29 13:29:23 +02:00 committed by GitHub
commit 342a082287
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 49 additions and 35 deletions

View File

@ -12,6 +12,8 @@ import com.joanzapata.iconify.fonts.MaterialModule;
import de.danoeh.antennapod.activity.SplashActivity;
import de.danoeh.antennapod.core.ApCoreEventBusIndex;
import de.danoeh.antennapod.core.ClientConfig;
import de.danoeh.antennapod.error.CrashReportWriter;
import de.danoeh.antennapod.error.RxJavaErrorHandlerSetup;
import de.danoeh.antennapod.spa.SPAUtil;
import org.greenrobot.eventbus.EventBus;
@ -38,6 +40,7 @@ public class PodcastApp extends Application {
super.onCreate();
Thread.setDefaultUncaughtExceptionHandler(new CrashReportWriter());
RxJavaErrorHandlerSetup.setupRxJavaErrorHandler();
if (BuildConfig.DEBUG) {
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder()

View File

@ -7,7 +7,7 @@ import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.TextView;
import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.error.CrashReportWriter;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.util.IntentUtils;

View File

@ -1,8 +1,9 @@
package de.danoeh.antennapod;
package de.danoeh.antennapod.error;
import android.os.Build;
import android.util.Log;
import de.danoeh.antennapod.BuildConfig;
import org.apache.commons.io.IOUtils;
import java.io.File;
@ -31,6 +32,11 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
@Override
public void uncaughtException(Thread thread, Throwable ex) {
write(ex);
defaultHandler.uncaughtException(thread, ex);
}
public static void write(Throwable exception) {
File path = getFile();
PrintWriter out = null;
try {
@ -41,14 +47,13 @@ public class CrashReportWriter implements Thread.UncaughtExceptionHandler {
out.println();
out.println("## StackTrace");
out.println("```");
ex.printStackTrace(out);
exception.printStackTrace(out);
out.println("```");
} catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e));
} finally {
IOUtils.closeQuietly(out);
}
defaultHandler.uncaughtException(thread, ex);
}
public static String getSystemInfo() {

View File

@ -0,0 +1,36 @@
package de.danoeh.antennapod.error;
import android.util.Log;
import de.danoeh.antennapod.BuildConfig;
import io.reactivex.exceptions.UndeliverableException;
import io.reactivex.plugins.RxJavaPlugins;
public class RxJavaErrorHandlerSetup {
private static final String TAG = "RxJavaErrorHandler";
private RxJavaErrorHandlerSetup() {
}
public static void setupRxJavaErrorHandler() {
RxJavaPlugins.setErrorHandler(exception -> {
if (exception instanceof UndeliverableException) {
// Probably just disposed because the fragment was left
Log.d(TAG, "Ignored exception: " + Log.getStackTraceString(exception));
return;
}
// Usually, undeliverable exceptions are wrapped in an UndeliverableException.
// If an undeliverable exception is a NPE (or some others), wrapping does not happen.
// AntennaPod threads might throw NPEs after disposing because we set controllers to null.
// Just swallow all exceptions here.
Log.e(TAG, Log.getStackTraceString(exception));
CrashReportWriter.write(exception);
if (BuildConfig.DEBUG) {
Thread.currentThread().getUncaughtExceptionHandler()
.uncaughtException(Thread.currentThread(), exception);
}
});
}
}

View File

@ -5,12 +5,11 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import de.danoeh.antennapod.BuildConfig;
import de.danoeh.antennapod.CrashReportWriter;
import de.danoeh.antennapod.error.CrashReportWriter;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.preferences.UserPreferences.EnqueueLocation;
import de.danoeh.antennapod.core.util.download.AutoUpdateManager;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
public class PreferenceUpgrader {
private static final String PREF_CONFIGURED_VERSION = "version_code";

View File

@ -9,7 +9,6 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.exception.RxJavaErrorHandlerSetup;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
import java.io.File;
@ -49,7 +48,6 @@ public class ClientConfig {
NetworkUtils.init(context);
AntennapodHttpClient.setCacheDirectory(new File(context.getCacheDir(), "okhttp"));
SleepTimerPreferences.init(context);
RxJavaErrorHandlerSetup.setupRxJavaErrorHandler();
NotificationUtils.createChannels(context);
initialized = true;
}

View File

@ -1,24 +0,0 @@
package de.danoeh.antennapod.core.util.exception;
import android.util.Log;
import io.reactivex.exceptions.UndeliverableException;
import io.reactivex.plugins.RxJavaPlugins;
public class RxJavaErrorHandlerSetup {
private RxJavaErrorHandlerSetup() {
}
public static void setupRxJavaErrorHandler() {
RxJavaPlugins.setErrorHandler(e -> {
if (e instanceof UndeliverableException) {
// Probably just disposed because the fragment was left
Log.d("RxJavaErrorHandler", "Ignored exception: " + Log.getStackTraceString(e));
return;
}
Thread.currentThread().getUncaughtExceptionHandler()
.uncaughtException(Thread.currentThread(), e);
});
}
}

View File

@ -1,7 +1,6 @@
package de.danoeh.antennapod.core;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.GooglePlayServicesNotAvailableException;
@ -15,7 +14,6 @@ import de.danoeh.antennapod.core.preferences.UserPreferences;
import de.danoeh.antennapod.core.service.download.AntennapodHttpClient;
import de.danoeh.antennapod.core.storage.PodDBAdapter;
import de.danoeh.antennapod.core.util.NetworkUtils;
import de.danoeh.antennapod.core.util.exception.RxJavaErrorHandlerSetup;
import de.danoeh.antennapod.core.util.gui.NotificationUtils;
import java.io.File;
@ -67,7 +65,6 @@ public class ClientConfig {
}
AntennapodHttpClient.setCacheDirectory(new File(context.getCacheDir(), "okhttp"));
SleepTimerPreferences.init(context);
RxJavaErrorHandlerSetup.setupRxJavaErrorHandler();
NotificationUtils.createChannels(context);
initialized = true;
}