Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash(es) caused by failing to dispose Rx observables #2669

Merged
merged 24 commits into from
Mar 19, 2019

Conversation

dbrant
Copy link
Collaborator

@dbrant dbrant commented Mar 19, 2019

You have numerous usages of Rx observables that are not properly contained in a Disposable object, and are not disposed when you leave the current activity or fragment. This can lead to all manner of crashes and subtle bugs.

@codecov-io
Copy link

Codecov Report

Merging #2669 into master will decrease coverage by <.01%.
The diff coverage is 0%.

Impacted file tree graph

@@            Coverage Diff            @@
##           master   #2669      +/-   ##
=========================================
- Coverage    2.77%   2.77%   -0.01%     
=========================================
  Files         261     261              
  Lines       12453   12465      +12     
  Branches     1130    1128       -2     
=========================================
  Hits          346     346              
- Misses      12080   12092      +12     
  Partials       27      27
Impacted Files Coverage Δ
...n/java/fr/free/nrw/commons/theme/BaseActivity.java 0% <0%> (ø) ⬆️
...ava/fr/free/nrw/commons/nearby/NearbyFragment.java 0% <0%> (ø) ⬆️
...ons/explore/categories/SearchCategoryFragment.java 0% <0%> (ø) ⬆️
...r/free/nrw/commons/contributions/MainActivity.java 0% <0%> (ø) ⬆️
...fr/free/nrw/commons/media/MediaDetailFragment.java 0% <0%> (ø) ⬆️
...ava/fr/free/nrw/commons/upload/UploadActivity.java 0% <0%> (ø) ⬆️
...w/commons/contributions/ContributionsFragment.java 0% <0%> (ø) ⬆️
...r/free/nrw/commons/auth/AuthenticatedActivity.java 0% <0%> (ø) ⬆️
...rw/commons/explore/images/SearchImageFragment.java 0% <0%> (ø) ⬆️
...w/commons/category/CategoryImagesListFragment.java 0% <0%> (ø) ⬆️
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3417d71...d1c83a6. Read the comment docs.

Copy link
Member

@domdomegg domdomegg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested 2.10.1-debug-RxFixes2~d1c83a619

Beta Commons Upload

As I was testing I got quite a few crashes when navigating quickly between activities. I think this happens in master although it felt more common testing this PR. I think #2668 might fix these and I'm unsure whether this PR makes this issue worse I'm going to wait for that to be merged first.

2019-03-19 20:12:42.780 3811-3811/fr.free.nrw.commons.beta E/ContributionsFragment: onFragmentResumed fr.free.nrw.commons.contributions.ContributionsListFragment
2019-03-19 20:12:42.995 3811-3811/fr.free.nrw.commons.beta E/ContributionsFragment: onFragmentDetached fr.free.nrw.commons.contributions.ContributionsListFragment
2019-03-19 20:12:42.996 3811-3863/fr.free.nrw.commons.beta E/ACRA: ACRA caught a UndeliverableException for fr.free.nrw.commons.beta
    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.io.InterruptedIOException
        at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
        at io.reactivex.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:50)
        at io.reactivex.Single.subscribe(Single.java:3438)
        at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
        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:764)
     Caused by: java.io.InterruptedIOException
        at okhttp3.internal.http2.Http2Stream.waitForIo(Http2Stream.java:642)
        at okhttp3.internal.http2.Http2Stream.takeHeaders(Http2Stream.java:150)
        at okhttp3.internal.http2.Http2Codec.readResponseHeaders(Http2Codec.java:131)
        at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:213)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:254)
        at okhttp3.RealCall.execute(RealCall.java:92)
        at fr.free.nrw.commons.mwapi.OkHttpJsonApiClient.lambda$getAchievements$2(OkHttpJsonApiClient.java:129)
        at fr.free.nrw.commons.mwapi.-$$Lambda$OkHttpJsonApiClient$e1yuTHfYTkBd47P3BZbbQnvFIto.call(Unknown Source:6)
        at io.reactivex.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:44)
        at io.reactivex.Single.subscribe(Single.java:3438) 
        at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89) 
        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:764) 
2019-03-19 20:12:43.002 3811-3876/fr.free.nrw.commons.beta E/ACRA: ACRA caught a UndeliverableException for fr.free.nrw.commons.beta
    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.io.InterruptedIOException
        at io.reactivex.plugins.RxJavaPlugins.onError(RxJavaPlugins.java:367)
        at io.reactivex.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:50)
        at io.reactivex.Single.subscribe(Single.java:3438)
        at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89)
        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:764)
     Caused by: java.io.InterruptedIOException
        at okhttp3.internal.http2.Http2Stream.waitForIo(Http2Stream.java:642)
        at okhttp3.internal.http2.Http2Stream.takeHeaders(Http2Stream.java:150)
        at okhttp3.internal.http2.Http2Codec.readResponseHeaders(Http2Codec.java:131)
        at okhttp3.internal.http.CallServerInterceptor.intercept(CallServerInterceptor.java:88)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.connection.ConnectInterceptor.intercept(ConnectInterceptor.java:45)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.cache.CacheInterceptor.intercept(CacheInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.internal.http.BridgeInterceptor.intercept(BridgeInterceptor.java:93)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RetryAndFollowUpInterceptor.intercept(RetryAndFollowUpInterceptor.java:126)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:213)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
        at okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
        at okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:254)
        at okhttp3.RealCall.execute(RealCall.java:92)
        at fr.free.nrw.commons.mwapi.OkHttpJsonApiClient.lambda$getUploadCount$0(OkHttpJsonApiClient.java:74)
        at fr.free.nrw.commons.mwapi.-$$Lambda$OkHttpJsonApiClient$9ZpGX0U5Zngts_jcRCFls7FtEIM.call(Unknown Source:4)
        at io.reactivex.internal.operators.single.SingleFromCallable.subscribeActual(SingleFromCallable.java:44)
        at io.reactivex.Single.subscribe(Single.java:3438) 
        at io.reactivex.internal.operators.single.SingleSubscribeOn$SubscribeOnObserver.run(SingleSubscribeOn.java:89) 
        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:764) 
2019-03-19 20:12:43.079 2713-739/com.google.android.googlequicksearchbox:search E/EntrySyncManager: Cannot determine account name: drop request
2019-03-19 20:12:43.079 2713-739/com.google.android.googlequicksearchbox:search E/NowController: Failed to access data from EntryProvider. ExecutionException.
    java.util.concurrent.ExecutionException: com.google.android.apps.gsa.sidekick.main.h.n: Could not complete scheduled request to refresh entries. ClientErrorCode: 3
        at com.google.common.util.concurrent.d.eA(SourceFile:85)
        at com.google.common.util.concurrent.d.get(SourceFile:23)
        at com.google.common.util.concurrent.l.get(SourceFile:2)
        at com.google.android.apps.gsa.staticplugins.nowstream.b.a.be.cbB(SourceFile:49)
        at com.google.android.apps.gsa.staticplugins.nowstream.b.a.be.cbA(SourceFile:181)
        at com.google.android.apps.gsa.staticplugins.nowstream.b.a.bh.run(Unknown Source:2)
        at com.google.android.apps.gsa.shared.util.concurrent.at.run(SourceFile:4)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at com.google.android.apps.gsa.shared.util.concurrent.b.g.run(Unknown Source:4)
        at com.google.android.apps.gsa.shared.util.concurrent.b.aw.run(SourceFile:4)
        at com.google.android.apps.gsa.shared.util.concurrent.b.aw.run(SourceFile:4)
        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:764)
        at com.google.android.apps.gsa.shared.util.concurrent.b.i.run(SourceFile:6)
     Caused by: com.google.android.apps.gsa.sidekick.main.h.n: Could not complete scheduled request to refresh entries. ClientErrorCode: 3
        at com.google.android.apps.gsa.staticplugins.nowstream.b.a.ar.az(Unknown Source:4)
        at com.google.common.util.concurrent.q.ap(SourceFile:7)
        at com.google.common.util.concurrent.p.run(SourceFile:32)
        at com.google.common.util.concurrent.bt.execute(SourceFile:3)
        at com.google.common.util.concurrent.d.b(SourceFile:275)
        at com.google.common.util.concurrent.d.addListener(SourceFile:135)
        at com.google.common.util.concurrent.p.b(SourceFile:3)
        at com.google.android.apps.gsa.shared.util.concurrent.h.a(SourceFile:16)
        at com.google.android.apps.gsa.shared.util.concurrent.h.a(SourceFile:13)
        at com.google.android.apps.gsa.staticplugins.nowstream.b.a.be.cbB(SourceFile:47)
        at com.google.android.apps.gsa.staticplugins.nowstream.b.a.be.cbA(SourceFile:181) 
        at com.google.android.apps.gsa.staticplugins.nowstream.b.a.bh.run(Unknown Source:2) 
        at com.google.android.apps.gsa.shared.util.concurrent.at.run(SourceFile:4) 
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458) 
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:458) 
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) 
        at com.google.android.apps.gsa.shared.util.concurrent.b.g.run(Unknown Source:4) 
        at com.google.android.apps.gsa.shared.util.concurrent.b.aw.run(SourceFile:4) 
        at com.google.android.apps.gsa.shared.util.concurrent.b.aw.run(SourceFile:4) 
        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:764) 
        at com.google.android.apps.gsa.shared.util.concurrent.b.i.run(SourceFile:6) 
2019-03-19 20:12:43.126 3811-3811/fr.free.nrw.commons.beta E/ContributionsFragment: onFragmentDetached fr.free.nrw.commons.contributions.ContributionsListFragment
2019-03-19 20:12:51.231 1961-2094/system_process E/SyncManager: Job params not found for 106441

@dbrant
Copy link
Collaborator Author

dbrant commented Mar 19, 2019

Ah yes, good observation. I should have noted that this PR is loosely "dependent" on #2668, since the proper disposal of Observables can cause them to dispatch an error (i.e. a network call being cancelled), and if the error is not handled properly, it will crash.

@dbrant
Copy link
Collaborator Author

dbrant commented Mar 19, 2019

@domdomegg I've gone ahead and consolidated the other two Rx-related patches into this one. Not sure why I didn't just do that from the beginning. Hopefully this is now simpler to test.

@domdomegg domdomegg self-requested a review March 19, 2019 21:04
Copy link
Member

@domdomegg domdomegg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested 2.10.1-debug-RxFixes2~14a2975ea

Beta Commons Upload

@domdomegg domdomegg merged commit 8474c04 into commons-app:master Mar 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants