From aa28a85747008976a9ca7ae3d976af036858b9cd Mon Sep 17 00:00:00 2001 From: litetex <40789489+litetex@users.noreply.github.com> Date: Sun, 24 Oct 2021 21:09:47 +0200 Subject: [PATCH] Added a workaround for not serializable exceptions --- .../error/EnsureExceptionSerializable.java | 103 ++++++++++++++++++ .../schabi/newpipe/error/ErrorActivity.java | 10 ++ .../playererror/PlayerErrorHandler.java | 3 +- 3 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java diff --git a/app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java b/app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java new file mode 100644 index 000000000..db94de5e5 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/error/EnsureExceptionSerializable.java @@ -0,0 +1,103 @@ +package org.schabi.newpipe.error; + +import android.util.Log; + +import androidx.annotation.NonNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +/** + * Ensures that a Exception is serializable. + * This is + */ +public final class EnsureExceptionSerializable { + private static final String TAG = "EnsureExSerializable"; + + private EnsureExceptionSerializable() { + // No instance + } + + /** + * Ensures that an exception is serializable. + *
+ * If that is not the case a {@link WorkaroundNotSerializableException} is created. + * + * @param exception + * @return if an exception is not serializable a new {@link WorkaroundNotSerializableException} + * otherwise the exception from the parameter + */ + public static Exception ensureSerializable(@NonNull final Exception exception) { + return checkIfSerializable(exception) + ? exception + : WorkaroundNotSerializableException.create(exception); + } + + public static boolean checkIfSerializable(@NonNull final Exception exception) { + try { + // Check by creating a new ObjectOutputStream which does the serialization + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(bos) + ) { + oos.writeObject(exception); + oos.flush(); + + bos.toByteArray(); + } + + return true; + } catch (final IOException ex) { + Log.d(TAG, "Exception is not serializable", ex); + return false; + } + } + + public static class WorkaroundNotSerializableException extends Exception { + protected WorkaroundNotSerializableException( + final Throwable notSerializableException, + final Throwable cause) { + super(notSerializableException.toString(), cause); + setStackTrace(notSerializableException.getStackTrace()); + } + + protected WorkaroundNotSerializableException(final Throwable notSerializableException) { + super(notSerializableException.toString()); + setStackTrace(notSerializableException.getStackTrace()); + } + + public static WorkaroundNotSerializableException create( + @NonNull final Exception notSerializableException + ) { + // Build a list of the exception + all causes + final List throwableList = new ArrayList<>(); + + int pos = 0; + Throwable throwableToProcess = notSerializableException; + + while (throwableToProcess != null) { + throwableList.add(throwableToProcess); + + pos++; + throwableToProcess = throwableToProcess.getCause(); + } + + // Reverse list so that it starts with the last one + Collections.reverse(throwableList); + + // Build exception stack + WorkaroundNotSerializableException cause = null; + for (final Throwable t : throwableList) { + cause = cause == null + ? new WorkaroundNotSerializableException(t) + : new WorkaroundNotSerializableException(t, cause); + } + + return cause; + } + + } +} diff --git a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java index c0d88c8ec..db3a92d4f 100644 --- a/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java +++ b/app/src/main/java/org/schabi/newpipe/error/ErrorActivity.java @@ -77,6 +77,16 @@ public class ErrorActivity extends AppCompatActivity { private ActivityErrorBinding activityErrorBinding; + /** + * Reports a new error by starting a new activity. + *
+ * Ensure that the data within errorInfo is serializable otherwise + * an exception will be thrown!
+ * {@link EnsureExceptionSerializable} might help. + * + * @param context + * @param errorInfo + */ public static void reportError(final Context context, final ErrorInfo errorInfo) { final Intent intent = new Intent(context, ErrorActivity.class); intent.putExtra(ERROR_INFO, errorInfo); diff --git a/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java b/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java index 4c8d9bc5f..626200ae1 100644 --- a/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java +++ b/app/src/main/java/org/schabi/newpipe/player/playererror/PlayerErrorHandler.java @@ -12,6 +12,7 @@ import androidx.preference.PreferenceManager; import com.google.android.exoplayer2.ExoPlaybackException; import org.schabi.newpipe.R; +import org.schabi.newpipe.error.EnsureExceptionSerializable; import org.schabi.newpipe.error.ErrorActivity; import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.UserAction; @@ -69,7 +70,7 @@ public class PlayerErrorHandler { ErrorActivity.reportError( context, new ErrorInfo( - exception, + EnsureExceptionSerializable.ensureSerializable(exception), UserAction.PLAY_STREAM, "Player error[type=" + exception.type + "] occurred while playing: " + info.getUrl(),