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(),