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 exception #2019

Merged
merged 1 commit into from
Dec 20, 2020
Merged

Conversation

samoylenkodmitry
Copy link
Contributor

Another rare crash that our monkey found, 2 crashes/day

Non-fatal Exception: java.util.ConcurrentModificationException
       at java.util.ArrayList$Itr.next(ArrayList.java:860)
       at leakcanary.internal.activity.db.HeapAnalysisTable$notifyUpdateOnMainThread$1.run(HeapAnalysisTable.kt:207)
       at android.os.Handler.handleCallback(Handler.java:790)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:164)
       at android.app.ActivityThread.main(ActivityThread.java:6494)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)

```
Non-fatal Exception: java.util.ConcurrentModificationException
       at java.util.ArrayList$Itr.next(ArrayList.java:860)
       at leakcanary.internal.activity.db.HeapAnalysisTable$notifyUpdateOnMainThread$1.run(HeapAnalysisTable.kt:207)
       at android.os.Handler.handleCallback(Handler.java:790)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loop(Looper.java:164)
       at android.app.ActivityThread.main(ActivityThread.java:6494)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
```
@pyricau
Copy link
Member

pyricau commented Dec 20, 2020

Thanks for the exception. Can you provide a repro scenario?

HeapAnalysisTable.updateListeners should only be accessed from the main thread, so this should never happens. If it's accessed from a background thread somewhere, we need to identify where and fix that. I don't think we should use thread safe data structure here unless we come up with a good reason for accessing updateListeners from a background thread.

@pyricau
Copy link
Member

pyricau commented Dec 20, 2020

I looked into this further. This isn't a concurrency issue, HeapAnalysisTable.updateListeners is only accessed from the main thread. It's the good old "Removed an entry from a list while iterating on it". Right now the two screens that have listeners will refresh themselves when triggered, ie remove and redisplay themselves, which triggers a removal of the listener.

However that works fine because there's usually only one listener at a time, so we foreach on the first entry, remove the first entry in that foreach, but then there's not a second entry to loop again so no crash.

The Monkey here probably found a way to have two screens in flight and cause this. It's a good find :)

@pyricau
Copy link
Member

pyricau commented Dec 20, 2020

I just reproduced by adding right after HeapAnalysisTable.onUpdate in HeapDumpsScreen.createView:

      HeapAnalysisTable.onUpdate {
      }

and then going to the heap dump screen and clicking "Dump Now". Confirmed this PR fixes the issue, merging.

@pyricau pyricau merged commit 860e635 into square:main Dec 20, 2020
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.

2 participants