Prevent exception from being serialized in ErrorInfo

The wrong @Decorator was put in the wrong place to mark the throwable fieldd as transient, now this is fixed and the exception is not serialized. So if a non-serializable throwable is passed, that's not an issue, since it's not going to be serialized. The need for EnsureExceptionSerializable is also gone.
This commit is contained in:
Stypox 2021-12-01 10:28:35 +01:00
parent 09d137f740
commit 397f93b079
No known key found for this signature in database
GPG Key ID: 4BDF1B40A49FDD23
7 changed files with 19 additions and 123 deletions

View File

@ -38,7 +38,6 @@ public class AcraReportSender implements ReportSender {
UserAction.UI_ERROR, UserAction.UI_ERROR,
ErrorInfo.SERVICE_NONE, ErrorInfo.SERVICE_NONE,
"ACRA report", "ACRA report",
R.string.app_ui_crash, R.string.app_ui_crash));
null));
} }
} }

View File

@ -1,103 +0,0 @@
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.
* <br/>
* 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<Throwable> 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;
}
}
}

View File

@ -2,6 +2,7 @@ package org.schabi.newpipe.error
import android.os.Parcelable import android.os.Parcelable
import androidx.annotation.StringRes import androidx.annotation.StringRes
import kotlinx.parcelize.IgnoredOnParcel
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import org.schabi.newpipe.R import org.schabi.newpipe.R
import org.schabi.newpipe.extractor.Info import org.schabi.newpipe.extractor.Info
@ -21,11 +22,14 @@ class ErrorInfo(
val userAction: UserAction, val userAction: UserAction,
val serviceName: String, val serviceName: String,
val request: String, val request: String,
val messageStringId: Int, val messageStringId: Int
@Transient // no need to store throwable, all data for report is in other variables
var throwable: Throwable? = null
) : Parcelable { ) : Parcelable {
// no need to store throwable, all data for report is in other variables
// also, the throwable might not be serializable, see TeamNewPipe/NewPipe#7302
@IgnoredOnParcel
var throwable: Throwable? = null
private constructor( private constructor(
throwable: Throwable, throwable: Throwable,
userAction: UserAction, userAction: UserAction,
@ -36,9 +40,10 @@ class ErrorInfo(
userAction, userAction,
serviceName, serviceName,
request, request,
getMessageStringId(throwable, userAction), getMessageStringId(throwable, userAction)
throwable ) {
) this.throwable = throwable
}
private constructor( private constructor(
throwable: List<Throwable>, throwable: List<Throwable>,
@ -50,9 +55,10 @@ class ErrorInfo(
userAction, userAction,
serviceName, serviceName,
request, request,
getMessageStringId(throwable.firstOrNull(), userAction), getMessageStringId(throwable.firstOrNull(), userAction)
throwable.firstOrNull() ) {
) this.throwable = throwable.firstOrNull()
}
// constructors with single throwable // constructors with single throwable
constructor(throwable: Throwable, userAction: UserAction, request: String) : constructor(throwable: Throwable, userAction: UserAction, request: String) :

View File

@ -20,10 +20,6 @@ class ErrorUtil {
/** /**
* Reports a new error by starting a new activity. * Reports a new error by starting a new activity.
* <br></br>
* Ensure that the data within errorInfo is serializable otherwise
* an exception will be thrown!<br></br>
* [EnsureExceptionSerializable] might help.
* *
* @param context * @param context
* @param errorInfo * @param errorInfo

View File

@ -90,8 +90,7 @@ public class SubscriptionsImportFragment extends BaseFragment {
new ErrorInfo(new String[]{}, UserAction.SUBSCRIPTION_IMPORT_EXPORT, new ErrorInfo(new String[]{}, UserAction.SUBSCRIPTION_IMPORT_EXPORT,
NewPipe.getNameOfService(currentServiceId), NewPipe.getNameOfService(currentServiceId),
"Service does not support importing subscriptions", "Service does not support importing subscriptions",
R.string.general_error, R.string.general_error));
null));
activity.finish(); activity.finish();
} }
} }

View File

@ -12,7 +12,6 @@ import androidx.preference.PreferenceManager;
import com.google.android.exoplayer2.ExoPlaybackException; import com.google.android.exoplayer2.ExoPlaybackException;
import org.schabi.newpipe.R; import org.schabi.newpipe.R;
import org.schabi.newpipe.error.EnsureExceptionSerializable;
import org.schabi.newpipe.error.ErrorInfo; import org.schabi.newpipe.error.ErrorInfo;
import org.schabi.newpipe.error.ErrorUtil; import org.schabi.newpipe.error.ErrorUtil;
import org.schabi.newpipe.error.UserAction; import org.schabi.newpipe.error.UserAction;
@ -70,7 +69,7 @@ public class PlayerErrorHandler {
ErrorUtil.createNotification( ErrorUtil.createNotification(
context, context,
new ErrorInfo( new ErrorInfo(
EnsureExceptionSerializable.ensureSerializable(exception), exception,
UserAction.PLAY_STREAM, UserAction.PLAY_STREAM,
"Player error[type=" + exception.type + "] occurred while playing: " "Player error[type=" + exception.type + "] occurred while playing: "
+ info.getUrl(), + info.getUrl(),

View File

@ -583,7 +583,7 @@ public class MissionAdapter extends Adapter<ViewHolder> implements Handler.Callb
ErrorUtil.createNotification(mContext, ErrorUtil.createNotification(mContext,
new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action, new ErrorInfo(ErrorInfo.Companion.throwableToStringList(mission.errObject), action,
service, request.toString(), reason, null)); service, request.toString(), reason));
} }
public void clearFinishedDownloads(boolean delete) { public void clearFinishedDownloads(boolean delete) {