Loader.java 源代码


package com.mbridge.msdk.playercommon.exoplayer2.upstream;

import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
import android.util.Log;
import com.mbridge.msdk.playercommon.exoplayer2.util.Assertions;
import com.mbridge.msdk.playercommon.exoplayer2.util.TraceUtil;
import com.mbridge.msdk.playercommon.exoplayer2.util.Util;
import java.io.IOException;
import java.util.concurrent.ExecutorService;

public final class Loader implements LoaderErrorThrower {
    public static final int DONT_RETRY = 2;
    public static final int DONT_RETRY_FATAL = 3;
    public static final int RETRY = 0;
    public static final int RETRY_RESET_ERROR_COUNT = 1;
    private LoadTask<? extends Loadable> currentTask;
    private final ExecutorService downloadExecutorService;
    private IOException fatalError;

    public interface Callback<T extends Loadable> {
        void onLoadCanceled(T t6, long j6, long j7, boolean z6);

        void onLoadCompleted(T t6, long j6, long j7);

        int onLoadError(T t6, long j6, long j7, IOException iOException);
    }

    public final class LoadTask<T extends Loadable> extends Handler implements Runnable {
        private static final int MSG_CANCEL = 1;
        private static final int MSG_END_OF_SOURCE = 2;
        private static final int MSG_FATAL_ERROR = 4;
        private static final int MSG_IO_EXCEPTION = 3;
        private static final int MSG_START = 0;
        private static final String TAG = "LoadTask";
        private Callback<T> callback;
        private volatile boolean canceled;
        private IOException currentError;
        public final int defaultMinRetryCount;
        private int errorCount;
        private volatile Thread executorThread;
        private final T loadable;
        private volatile boolean released;
        private final long startTimeMs;

        public LoadTask(Looper looper, T t6, Callback<T> callback, int i6, long j6) {
            super(looper);
            this.loadable = t6;
            this.callback = callback;
            this.defaultMinRetryCount = i6;
            this.startTimeMs = j6;
        }

        private void execute() {
            this.currentError = null;
            Loader.this.downloadExecutorService.execute(Loader.this.currentTask);
        }

        private void finish() {
            Loader.this.currentTask = null;
        }

        private long getRetryDelayMillis() {
            return Math.min((this.errorCount - 1) * 1000, 5000);
        }

        public final void cancel(boolean z6) {
            this.released = z6;
            this.currentError = null;
            if (hasMessages(0)) {
                removeMessages(0);
                if (!z6) {
                    sendEmptyMessage(1);
                }
            } else {
                this.canceled = true;
                this.loadable.cancelLoad();
                if (this.executorThread != null) {
                    this.executorThread.interrupt();
                }
            }
            if (z6) {
                finish();
                long elapsedRealtime = SystemClock.elapsedRealtime();
                this.callback.onLoadCanceled(this.loadable, elapsedRealtime, elapsedRealtime - this.startTimeMs, true);
                this.callback = null;
            }
        }

        @Override
        public final void handleMessage(Message message) {
            if (this.released) {
                return;
            }
            int i6 = message.what;
            if (i6 == 0) {
                execute();
                return;
            }
            if (i6 != 4) {
                finish();
                long elapsedRealtime = SystemClock.elapsedRealtime();
                long j6 = elapsedRealtime - this.startTimeMs;
                if (this.canceled) {
                    this.callback.onLoadCanceled(this.loadable, elapsedRealtime, j6, false);
                    return;
                }
                int i7 = message.what;
                int i8 = 1;
                if (i7 != 1) {
                    if (i7 != 2) {
                        if (i7 == 3) {
                            IOException iOException = (IOException) message.obj;
                            this.currentError = iOException;
                            int onLoadError = this.callback.onLoadError(this.loadable, elapsedRealtime, j6, iOException);
                            if (onLoadError == 3) {
                                Loader.this.fatalError = this.currentError;
                                return;
                            } else {
                                if (onLoadError != 2) {
                                    if (onLoadError != 1) {
                                        i8 = 1 + this.errorCount;
                                    }
                                    this.errorCount = i8;
                                    start(getRetryDelayMillis());
                                    return;
                                }
                                return;
                            }
                        }
                        return;
                    }
                    try {
                        this.callback.onLoadCompleted(this.loadable, elapsedRealtime, j6);
                        return;
                    } catch (RuntimeException e6) {
                        Log.e(TAG, "Unexpected exception handling load completed", e6);
                        Loader.this.fatalError = new UnexpectedLoaderException(e6);
                        return;
                    }
                }
                this.callback.onLoadCanceled(this.loadable, elapsedRealtime, j6, false);
                return;
            }
            throw ((Error) message.obj);
        }

        public final void maybeThrowError(int i6) throws IOException {
            IOException iOException = this.currentError;
            if (iOException != null && this.errorCount > i6) {
                throw iOException;
            }
        }

        @Override
        public final void run() {
            try {
                this.executorThread = Thread.currentThread();
                if (!this.canceled) {
                    TraceUtil.beginSection("load:" + this.loadable.getClass().getSimpleName());
                    try {
                        this.loadable.load();
                        TraceUtil.endSection();
                    } catch (Throwable th) {
                        TraceUtil.endSection();
                        throw th;
                    }
                }
                if (!this.released) {
                    sendEmptyMessage(2);
                }
            } catch (IOException e6) {
                if (!this.released) {
                    obtainMessage(3, e6).sendToTarget();
                }
            } catch (OutOfMemoryError e7) {
                Log.e(TAG, "OutOfMemory error loading stream", e7);
                if (!this.released) {
                    obtainMessage(3, new UnexpectedLoaderException(e7)).sendToTarget();
                }
            } catch (Error e8) {
                Log.e(TAG, "Unexpected error loading stream", e8);
                if (!this.released) {
                    obtainMessage(4, e8).sendToTarget();
                }
                throw e8;
            } catch (InterruptedException unused) {
                Assertions.checkState(this.canceled);
                if (!this.released) {
                    sendEmptyMessage(2);
                }
            } catch (Exception e9) {
                Log.e(TAG, "Unexpected exception loading stream", e9);
                if (!this.released) {
                    obtainMessage(3, new UnexpectedLoaderException(e9)).sendToTarget();
                }
            }
        }

        public final void start(long j6) {
            boolean z6;
            if (Loader.this.currentTask == null) {
                z6 = true;
            } else {
                z6 = false;
            }
            Assertions.checkState(z6);
            Loader.this.currentTask = this;
            if (j6 > 0) {
                sendEmptyMessageDelayed(0, j6);
            } else {
                execute();
            }
        }
    }

    public interface Loadable {
        void cancelLoad();

        void load() throws IOException, InterruptedException;
    }

    public interface ReleaseCallback {
        void onLoaderReleased();
    }

    public static final class ReleaseTask implements Runnable {
        private final ReleaseCallback callback;

        public ReleaseTask(ReleaseCallback releaseCallback) {
            this.callback = releaseCallback;
        }

        @Override
        public final void run() {
            this.callback.onLoaderReleased();
        }
    }

    public @interface RetryAction {
    }

    public static final class UnexpectedLoaderException extends IOException {
        public UnexpectedLoaderException(Throwable th) {
            super("Unexpected " + th.getClass().getSimpleName() + ": " + th.getMessage(), th);
        }
    }

    public Loader(String str) {
        this.downloadExecutorService = Util.newSingleThreadExecutor(str);
    }

    public final void cancelLoading() {
        this.currentTask.cancel(false);
    }

    public final boolean isLoading() {
        if (this.currentTask != null) {
            return true;
        }
        return false;
    }

    @Override
    public final void maybeThrowError() throws IOException {
        maybeThrowError(Integer.MIN_VALUE);
    }

    public final void release() {
        release(null);
    }

    public final <T extends Loadable> long startLoading(T t6, Callback<T> callback, int i6) {
        boolean z6;
        Looper myLooper = Looper.myLooper();
        if (myLooper != null) {
            z6 = true;
        } else {
            z6 = false;
        }
        Assertions.checkState(z6);
        this.fatalError = null;
        long elapsedRealtime = SystemClock.elapsedRealtime();
        new LoadTask(myLooper, t6, callback, i6, elapsedRealtime).start(0L);
        return elapsedRealtime;
    }

    @Override
    public final void maybeThrowError(int i6) throws IOException {
        IOException iOException = this.fatalError;
        if (iOException == null) {
            LoadTask<? extends Loadable> loadTask = this.currentTask;
            if (loadTask != null) {
                if (i6 == Integer.MIN_VALUE) {
                    i6 = loadTask.defaultMinRetryCount;
                }
                loadTask.maybeThrowError(i6);
                return;
            }
            return;
        }
        throw iOException;
    }

    public final void release(ReleaseCallback releaseCallback) {
        LoadTask<? extends Loadable> loadTask = this.currentTask;
        if (loadTask != null) {
            loadTask.cancel(true);
        }
        if (releaseCallback != null) {
            this.downloadExecutorService.execute(new ReleaseTask(releaseCallback));
        }
        this.downloadExecutorService.shutdown();
    }
}