Creating a download task, and cancelling (disposing it) while download is ongoing results in SocketException which is thrown after disposable which results in UndeliverableException.
Version of software affected
Library version: 1.1.4
Demo app from master branch (commit: 0275362c850c81d70ee1b730597e39b6e4bd2040) [if RxJavaPlugins.setErrorHandler is removed from BaseApplication]
Failure Rate
100 %
Regression ?
Yes.
But not sure on the exact version when regression happened. The old lib version (from ~2019 ) does not have this problem.
Wait until download started (i.e you get onNext callback with progress)
Cancel the download by calling dispose on disposable variable
The fatal error in the library will crash the application
Expected Result
Create Download Task
Wait until download started
Cancel the download
Download is cancelled & App is not crashed
Actual Result
Create Download Task
Wait until download started
Cancel the download
App crashed
Crashlogs
Crashlog
```
2022-06-29 17:48:51.650 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed
2022-06-29 17:48:51.650 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
2022-06-29 17:48:51.650 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.innerError(FlowableFlatMap.java:608)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onError(FlowableFlatMap.java:672)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.onError(FlowableGenerate.java:189)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:114)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate.subscribeActual(FlowableGenerate.java:52)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14918)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14865)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163)
2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap.java:282)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:663)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFromObservable$SubscriberObserver.onNext(FlowableFromObservable.java:54)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:47)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Observable.subscribe(Observable.java:12267)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.lang.Thread.run(Thread.java:923)
2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: Caused by: java.net.SocketException: Socket closed
2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:209)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:144)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.InputStreamSource.read(Okio.kt:93)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:159)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43)
2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okhttp3.internal.http1.Http1Codec$AbstractSource.read(Http1Codec.java:363)
2022-06-29 17:48:51.656 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:407)
2022-06-29 17:48:51.656 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43)
2022-06-29 17:48:51.656 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.ForwardingSource.read(ForwardingSource.kt:29)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at retrofit2.OkHttpCall$ExceptionCatchingResponseBody$1.read(OkHttpCall.java:288)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:440)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.io.InputStream.read(InputStream.java:101)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:152)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:123)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:62)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:53)
2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:109)
2022-06-29 17:48:51.658 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: ... 22 more
2022-06-29 17:48:51.658 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed
2022-06-29 17:48:51.658 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.innerError(FlowableFlatMap.java:608)
2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onError(FlowableFlatMap.java:672)
2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.onError(FlowableGenerate.java:189)
2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:114)
2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656)
2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate.subscribeActual(FlowableGenerate.java:52)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14918)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14865)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap.java:282)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:663)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFromObservable$SubscriberObserver.onNext(FlowableFromObservable.java:54)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:47)
2022-06-29 17:48:51.661 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Observable.subscribe(Observable.java:12267)
2022-06-29 17:48:51.661 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2022-06-29 17:48:51.663 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2022-06-29 17:48:51.663 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.lang.Thread.run(Thread.java:923)
--------- beginning of crash
2022-06-29 17:48:51.663 4277-4356/zlc.season.rxdownload.kotlin_demo E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-6
Process: zlc.season.rxdownload.kotlin_demo, PID: 4277
io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed
at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.innerError(FlowableFlatMap.java:608)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onError(FlowableFlatMap.java:672)
at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.onError(FlowableGenerate.java:189)
at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:114)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656)
at io.reactivex.internal.operators.flowable.FlowableGenerate.subscribeActual(FlowableGenerate.java:52)
at io.reactivex.Flowable.subscribe(Flowable.java:14918)
at io.reactivex.Flowable.subscribe(Flowable.java:14865)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap.java:282)
at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:663)
at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129)
at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68)
at io.reactivex.internal.operators.flowable.FlowableFromObservable$SubscriberObserver.onNext(FlowableFromObservable.java:54)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58)
at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:47)
at io.reactivex.Observable.subscribe(Observable.java:12267)
at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Caused by: java.net.SocketException: Socket closed
at java.net.SocketInputStream.read(SocketInputStream.java:209)
at java.net.SocketInputStream.read(SocketInputStream.java:144)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815)
at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788)
at okio.InputStreamSource.read(Okio.kt:93)
at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:159)
at okio.RealBufferedSource.read(RealBufferedSource.kt:43)
at okhttp3.internal.http1.Http1Codec$AbstractSource.read(Http1Codec.java:363)
2022-06-29 17:48:51.663 4277-4357/? W/System.err: Caused by: java.net.SocketException: Socket closed
2022-06-29 17:48:51.663 4277-4357/? W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:209)
2022-06-29 17:48:51.663 4277-4357/? W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:144)
2022-06-29 17:48:51.664 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936)
2022-06-29 17:48:51.664 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900)
2022-06-29 17:48:51.664 4277-4356/? E/AndroidRuntime: at okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:407)
at okio.RealBufferedSource.read(RealBufferedSource.kt:43)
at okio.ForwardingSource.read(ForwardingSource.kt:29)
at retrofit2.OkHttpCall$ExceptionCatchingResponseBody$1.read(OkHttpCall.java:288)
at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:440)
at java.io.InputStream.read(InputStream.java:101)
at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:152)
at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:123)
at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:62)
at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:53)
at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:109)
... 22 more
2022-06-29 17:48:51.665 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815)
2022-06-29 17:48:51.665 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788)
2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okio.InputStreamSource.read(Okio.kt:93)
2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:159)
2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43)
2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okhttp3.internal.http1.Http1Codec$AbstractSource.read(Http1Codec.java:363)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:407)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okio.ForwardingSource.read(ForwardingSource.kt:29)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at retrofit2.OkHttpCall$ExceptionCatchingResponseBody$1.read(OkHttpCall.java:288)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:440)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at java.io.InputStream.read(InputStream.java:101)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:152)
2022-06-29 17:48:51.666 4277-4357/? W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:123)
2022-06-29 17:48:51.667 4277-4357/? W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:62)
2022-06-29 17:48:51.667 4277-4357/? W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:53)
2022-06-29 17:48:51.667 4277-4357/? W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:109)
2022-06-29 17:48:51.667 4277-4357/? W/System.err: ... 22 more
2022-06-29 17:48:51.667 4277-4357/? I/Process: Sending signal. PID: 4277 SIG: 9
2022-06-29 17:48:51.667 4277-4344/? W/System.err: io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed
```
Workaround
I know by setting the RxJavaPlugins.setErrorHandler we can avoid this crash, but is it a good practice to ignore silently errors like this ?
Investigations
I think there is a bug in the library, specifically in: RangeDownloader::InnerDownloader::rangeSave which located here: rxdownload4/src/main/java/zlc/season/rxdownload4/downloader/RangeDownloader.kt
Function rangeSave creates a Flowable which reads from InputStream in generator and closes the stream in disposeState
Here is the picture with code for the above:
The reading from socket is a blocking call (val readLen = source.read(buffer)) which waits/blocks until we have received 8k bytes, then execution continues.
Now, while the reading is ongoing/thread is blocked, it's possible for user to dispose the disposable (which is done on another thread).
In which case, as soon as socket is closed, the blocking read will throw java.net.SocketException: Socket closed
I think this is a bug that we need to solve somehow, if user disposes the download, the socket throws, but this is done after user has disposed the download, which means this error will go to RxJava default error handler, and not to our onError from subscribeBy
So, I think we should catch this error somehow (since this is expected error, as we are closing socket in the middle of the read), or prevent this error from happening ?
This is the closest I've got to solving this problem:
Patch:
We know that read will throw SocketException with Socket closed, but we don't wan to propagae this error to the user since user has disposed the download, and we don't want to crash the app. So we look for this specific error, and if it is - ignore it, otherwise re-throw error (We don't want to break a use-case when there was a real socket error while download is going, we want to throw in that case so it can end up in our onError from subscribeBy)
But, to be honest, I don't really like this fix. It looks into the error message, does string == check. But, I'm curios to see what maintainer thinks of this issue & if there is a more elegant way to fix this? Maybe we can somehow close the stream without making it throw?
I found this interesting suggestion on StackOverflow: https://stackoverflow.com/a/23623114 but this does not apply to use, as InputStream does not have shutdownInput method.
Hi all,
Summary:
Creating a download task, and cancelling (disposing it) while download is ongoing results in SocketException which is thrown after disposable which results in UndeliverableException.
Version of software affected
Failure Rate
100 %
Regression ?
Yes. But not sure on the exact version when regression happened. The old lib version (from ~2019 ) does not have this problem.
Steps
val disposable = Task(url).download).subscribeBy(....)
)onNext
callback with progress)dispose
ondisposable
variableExpected Result
Actual Result
Crashlogs
Crashlog
``` 2022-06-29 17:48:51.650 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed 2022-06-29 17:48:51.650 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367) 2022-06-29 17:48:51.650 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.innerError(FlowableFlatMap.java:608) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onError(FlowableFlatMap.java:672) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.onError(FlowableGenerate.java:189) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:114) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate.subscribeActual(FlowableGenerate.java:52) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14918) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14865) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163) 2022-06-29 17:48:51.651 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap.java:282) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:663) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFromObservable$SubscriberObserver.onNext(FlowableFromObservable.java:54) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:47) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Observable.subscribe(Observable.java:12267) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) 2022-06-29 17:48:51.652 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266) 2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) 2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.lang.Thread.run(Thread.java:923) 2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: Caused by: java.net.SocketException: Socket closed 2022-06-29 17:48:51.653 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:209) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:144) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.InputStreamSource.read(Okio.kt:93) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:159) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43) 2022-06-29 17:48:51.654 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okhttp3.internal.http1.Http1Codec$AbstractSource.read(Http1Codec.java:363) 2022-06-29 17:48:51.656 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:407) 2022-06-29 17:48:51.656 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43) 2022-06-29 17:48:51.656 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.ForwardingSource.read(ForwardingSource.kt:29) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at retrofit2.OkHttpCall$ExceptionCatchingResponseBody$1.read(OkHttpCall.java:288) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:440) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at java.io.InputStream.read(InputStream.java:101) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:152) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:123) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:62) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:53) 2022-06-29 17:48:51.657 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:109) 2022-06-29 17:48:51.658 4277-4356/zlc.season.rxdownload.kotlin_demo W/System.err: ... 22 more 2022-06-29 17:48:51.658 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed 2022-06-29 17:48:51.658 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367) 2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.innerError(FlowableFlatMap.java:608) 2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onError(FlowableFlatMap.java:672) 2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.onError(FlowableGenerate.java:189) 2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:114) 2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656) 2022-06-29 17:48:51.659 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate.subscribeActual(FlowableGenerate.java:52) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14918) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Flowable.subscribe(Flowable.java:14865) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap.java:282) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:663) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.flowable.FlowableFromObservable$SubscriberObserver.onNext(FlowableFromObservable.java:54) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58) 2022-06-29 17:48:51.660 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:47) 2022-06-29 17:48:51.661 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Observable.subscribe(Observable.java:12267) 2022-06-29 17:48:51.661 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96) 2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578) 2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) 2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) 2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266) 2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) 2022-06-29 17:48:51.662 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) 2022-06-29 17:48:51.663 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) 2022-06-29 17:48:51.663 4277-4357/zlc.season.rxdownload.kotlin_demo W/System.err: at java.lang.Thread.run(Thread.java:923) --------- beginning of crash 2022-06-29 17:48:51.663 4277-4356/zlc.season.rxdownload.kotlin_demo E/AndroidRuntime: FATAL EXCEPTION: RxCachedThreadScheduler-6 Process: zlc.season.rxdownload.kotlin_demo, PID: 4277 io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367) at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.innerError(FlowableFlatMap.java:608) at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onError(FlowableFlatMap.java:672) at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.onError(FlowableGenerate.java:189) at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:114) at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onSubscribe(FlowableFlatMap.java:656) at io.reactivex.internal.operators.flowable.FlowableGenerate.subscribeActual(FlowableGenerate.java:52) at io.reactivex.Flowable.subscribe(Flowable.java:14918) at io.reactivex.Flowable.subscribe(Flowable.java:14865) at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.onNext(FlowableFlatMap.java:163) at io.reactivex.internal.operators.flowable.FlowableFlatMap$MergeSubscriber.tryEmit(FlowableFlatMap.java:282) at io.reactivex.internal.operators.flowable.FlowableFlatMap$InnerSubscriber.onNext(FlowableFlatMap.java:663) at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.drain(FlowableOnBackpressureLatest.java:129) at io.reactivex.internal.operators.flowable.FlowableOnBackpressureLatest$BackpressureLatestSubscriber.onNext(FlowableOnBackpressureLatest.java:68) at io.reactivex.internal.operators.flowable.FlowableFromObservable$SubscriberObserver.onNext(FlowableFromObservable.java:54) at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeOnObserver.onNext(ObservableSubscribeOn.java:58) at retrofit2.adapter.rxjava2.CallExecuteObservable.subscribeActual(CallExecuteObservable.java:47) at io.reactivex.Observable.subscribe(Observable.java:12267) at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96) at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578) at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66) at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57) at java.util.concurrent.FutureTask.run(FutureTask.java:266) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641) at java.lang.Thread.run(Thread.java:923) Caused by: java.net.SocketException: Socket closed at java.net.SocketInputStream.read(SocketInputStream.java:209) at java.net.SocketInputStream.read(SocketInputStream.java:144) at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936) at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900) at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815) at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788) at okio.InputStreamSource.read(Okio.kt:93) at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:159) at okio.RealBufferedSource.read(RealBufferedSource.kt:43) at okhttp3.internal.http1.Http1Codec$AbstractSource.read(Http1Codec.java:363) 2022-06-29 17:48:51.663 4277-4357/? W/System.err: Caused by: java.net.SocketException: Socket closed 2022-06-29 17:48:51.663 4277-4357/? W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:209) 2022-06-29 17:48:51.663 4277-4357/? W/System.err: at java.net.SocketInputStream.read(SocketInputStream.java:144) 2022-06-29 17:48:51.664 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readFromSocket(ConscryptEngineSocket.java:936) 2022-06-29 17:48:51.664 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.processDataFromSocket(ConscryptEngineSocket.java:900) 2022-06-29 17:48:51.664 4277-4356/? E/AndroidRuntime: at okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:407) at okio.RealBufferedSource.read(RealBufferedSource.kt:43) at okio.ForwardingSource.read(ForwardingSource.kt:29) at retrofit2.OkHttpCall$ExceptionCatchingResponseBody$1.read(OkHttpCall.java:288) at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:440) at java.io.InputStream.read(InputStream.java:101) at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:152) at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:123) at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:62) at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:53) at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:109) ... 22 more 2022-06-29 17:48:51.665 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.readUntilDataAvailable(ConscryptEngineSocket.java:815) 2022-06-29 17:48:51.665 4277-4357/? W/System.err: at com.android.org.conscrypt.ConscryptEngineSocket$SSLInputStream.read(ConscryptEngineSocket.java:788) 2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okio.InputStreamSource.read(Okio.kt:93) 2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okio.AsyncTimeout$source$1.read(AsyncTimeout.kt:159) 2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43) 2022-06-29 17:48:51.665 4277-4357/? W/System.err: at okhttp3.internal.http1.Http1Codec$AbstractSource.read(Http1Codec.java:363) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okhttp3.internal.http1.Http1Codec$FixedLengthSource.read(Http1Codec.java:407) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okio.RealBufferedSource.read(RealBufferedSource.kt:43) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okio.ForwardingSource.read(ForwardingSource.kt:29) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at retrofit2.OkHttpCall$ExceptionCatchingResponseBody$1.read(OkHttpCall.java:288) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at okio.RealBufferedSource$inputStream$1.read(RealBufferedSource.kt:440) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at java.io.InputStream.read(InputStream.java:101) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:152) 2022-06-29 17:48:51.666 4277-4357/? W/System.err: at zlc.season.rxdownload4.downloader.RangeDownloader$InnerDownloader$rangeSave$2.accept(RangeDownloader.kt:123) 2022-06-29 17:48:51.667 4277-4357/? W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:62) 2022-06-29 17:48:51.667 4277-4357/? W/System.err: at io.reactivex.internal.operators.flowable.FlowableInternalHelper$SimpleBiGenerator.apply(FlowableInternalHelper.java:53) 2022-06-29 17:48:51.667 4277-4357/? W/System.err: at io.reactivex.internal.operators.flowable.FlowableGenerate$GeneratorSubscription.request(FlowableGenerate.java:109) 2022-06-29 17:48:51.667 4277-4357/? W/System.err: ... 22 more 2022-06-29 17:48:51.667 4277-4357/? I/Process: Sending signal. PID: 4277 SIG: 9 2022-06-29 17:48:51.667 4277-4344/? W/System.err: io.reactivex.exceptions.UndeliverableException: The exception could not be delivered to the consumer because it has already canceled/disposed the flow or the exception has nowhere to go to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | java.net.SocketException: Socket closed ```Workaround
I know by setting the
RxJavaPlugins.setErrorHandler
we can avoid this crash, but is it a good practice to ignore silently errors like this ?Investigations
I think there is a bug in the library, specifically in:
RangeDownloader::InnerDownloader::rangeSave
which located here:rxdownload4/src/main/java/zlc/season/rxdownload4/downloader/RangeDownloader.kt
Function
rangeSave
creates aFlowable
which reads fromInputStream
ingenerator
and closes the stream indisposeState
Here is the picture with code for the above:![info](https://user-images.githubusercontent.com/11800090/176365239-7b7aaac6-1060-4ae8-a08b-0a4138c6a40d.png)
The reading from socket is a blocking call (
val readLen = source.read(buffer)
) which waits/blocks until we have received 8k bytes, then execution continues.Now, while the reading is ongoing/thread is blocked, it's possible for user to dispose the disposable (which is done on another thread). In which case, as soon as socket is closed, the blocking
read
will throwjava.net.SocketException: Socket closed
I think this is a bug that we need to solve somehow, if user disposes the download, the socket throws, but this is done after user has disposed the download, which means this error will go to RxJava default error handler, and not to our
onError
fromsubscribeBy
So, I think we should catch this error somehow (since this is expected error, as we are closing socket in the middle of the read), or prevent this error from happening ?
This is the closest I've got to solving this problem: Patch:
Fix explanation:
We know that
read
will throwSocketException
withSocket closed
, but we don't wan to propagae this error to the user since user has disposed the download, and we don't want to crash the app. So we look for this specific error, and if it is - ignore it, otherwise re-throw error (We don't want to break a use-case when there was a real socket error while download is going, we want to throw in that case so it can end up in ouronError
fromsubscribeBy
)But, to be honest, I don't really like this fix. It looks into the error message, does string
==
check. But, I'm curios to see what maintainer thinks of this issue & if there is a more elegant way to fix this? Maybe we can somehow close the stream without making it throw? I found this interesting suggestion on StackOverflow: https://stackoverflow.com/a/23623114 but this does not apply to use, asInputStream
does not haveshutdownInput
method.PS. This issue looks similar to this reported before, but there was no fix provided as far as I can see: https://github.com/ssseasonnn/RxDownload/issues/308#issuecomment-602573265
PSS. Thanks for making this lib, I think it's an amazing lib, and I've used it in the past, which was a breeze!