Leakcanary: Android System Autofill Leak

Created on 10 Sep 2019  ยท  6Comments  ยท  Source: square/leakcanary

(Reopen of #776 since it appears closed issues are not monitored)

LeakTrace information

ApplicationLeak(className=com.myapp.Activity, leakTrace=
โ”ฌ
โ”œโ”€ android.app.assist.AssistStructure$SendChannel
โ”‚    Leaking: UNKNOWN
โ”‚    GC Root: Global variable in native code
โ”‚    โ†“ AssistStructure$SendChannel.mAssistStructure
โ”‚                                  ~~~~~~~~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure.mWindowNodes
โ”‚                      ~~~~~~~~~~~~
โ”œโ”€ java.util.ArrayList
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ ArrayList.elementData
โ”‚                ~~~~~~~~~~~
โ”œโ”€ java.lang.Object[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array Object[].[0]
โ”‚                     ~~~
โ”œโ”€ android.app.assist.AssistStructure$WindowNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$WindowNode.mRoot
โ”‚                                 ~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[0]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[1]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[0]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[0]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[5]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mText
โ”‚                               ~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNodeText
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNodeText.mText
โ”‚                                   ~~~~~
โ”œโ”€ android.text.SpannableStringBuilder
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ SpannableStringBuilder.mSpans
โ”‚                             ~~~~~~
โ”œโ”€ java.lang.Object[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array Object[].[0]
โ”‚                     ~~~
โ”œโ”€ com.myapp.spans.ClickSpan
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ ClickSpan.listener
โ”‚                ~~~~~~~~
โ”œโ”€ com.myapp.MyFragment
โ”‚    Leaking: YES (Fragment#mFragmentManager is null)
โ”‚    โ†“ MyFragment.textBox
โ”œโ”€ com.myapp.views.MyTextView
โ”‚    Leaking: YES (MyFragment is leaking and View.mContext references a destroyed activity)
โ”‚    mContext instance of com.myapp.Activity with mDestroyed = true
โ”‚    View#mParent is set
โ”‚    View#mAttachInfo is null (view detached)
โ”‚    View.mWindowAttachCount = 1
โ”‚    โ†“ MyTextView.mContext
โ•ฐโ†’ com.myapp.Activity
โ€‹     Leaking: YES (MyTextView is leaking and Activity#mDestroyed is true and ObjectWatcher was watching this)
โ€‹     key = 61f611e3-b757-4c34-9a4f-d5369ba35865
โ€‹     watchDurationMillis = 4924
โ€‹     retainedDurationMillis = -89
, retainedHeapByteSize=124)

This is on OnePlus 7 Pro (GM1913) running Android 9.

leak

Most helpful comment

You can add your own custom "library leak patterns", and those could possibly match your own code. However LeakCanary has to analyze the heap to know what each leak is about, so you'll pay the cost anyway, it's only a classification difference. You're better off actually fixing that leak ;) . Even android framework leaks can be fixed with enough imagination and hackery.

All 6 comments

I've been using version 2.0-beta-5 which should include the fix for this, however I'm still having LeakCanary report the following:

Known leak pattern: instance field android.app.assist.AssistStructure$ViewNodeText#mText
Description: AssistStructure (google assistant / autofill) holds on to text spannables on the screen. TextView.ChangeWatcher and android.widget.Editor end up in spans and typically hold on to the view hierarchy
1347879 bytes retained
โ”ฌ
โ”œโ”€ android.app.assist.AssistStructure$SendChannel
โ”‚    Leaking: UNKNOWN
โ”‚    GC Root: Global variable in native code
โ”‚    โ†“ AssistStructure$SendChannel.mAssistStructure
โ”‚                                  ~~~~~~~~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure.mWindowNodes
โ”‚                      ~~~~~~~~~~~~
โ”œโ”€ java.util.ArrayList
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ ArrayList.elementData
โ”‚                ~~~~~~~~~~~
โ”œโ”€ java.lang.Object[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array Object[].[0]
โ”‚                     ~~~
โ”œโ”€ android.app.assist.AssistStructure$WindowNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$WindowNode.mRoot
โ”‚                                 ~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[0]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[0]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[1]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[0]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[0]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mChildren
โ”‚                               ~~~~~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array AssistStructure$ViewNode[].[6]
โ”‚                                       ~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNode
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNode.mText
โ”‚                               ~~~~~
โ”œโ”€ android.app.assist.AssistStructure$ViewNodeText
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ AssistStructure$ViewNodeText.mText
โ”‚                                   ~~~~~
โ”œโ”€ android.text.SpannableStringBuilder
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ SpannableStringBuilder.mSpans
โ”‚                             ~~~~~~
โ”œโ”€ java.lang.Object[]
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ array Object[].[0]
โ”‚                     ~~~
โ”œโ”€ RedactedActivity$StyleableClickSpan
โ”‚    Leaking: UNKNOWN
โ”‚    โ†“ RedactedActivity$StyleableClickSpan.onClick
โ”‚                                        ~~~~~~~
โ”œโ”€ RedactedTextViewExtensionsKt$sam$java_lang_Runnable$0
โ”‚    Leaking: UNKNOWN
โ”‚    Anonymous class implementing java.lang.Runnable
โ”‚    โ†“ TextViewExtensionsKt$sam$java_lang_Runnable$0.function
โ”‚                                                    ~~~~~~~~
โ”œโ”€ RedactedFragment$onViewCreated$3
โ”‚    Leaking: UNKNOWN
โ”‚    Anonymous subclass of kotlin.jvm.internal.Lambda
โ”‚    โ†“ RedactedFragment$onViewCreated$3.this$0
โ”‚                                    ~~~~~~
โ•ฐโ†’ RedactedFragment
โ€‹     Leaking: YES (Fragment#mFragmentManager is null and ObjectWatcher was watching this)
โ€‹     key = f0834154-b892-4b6e-a0ba-3b624b675fba
โ€‹     watchDurationMillis = 5401
โ€‹     retainedDurationMillis = 389


METADATA

Build.VERSION.SDK_INT: 28
Build.MANUFACTURER: Google
LeakCanary version: 2.0-beta-5
App process name: redacted
Analysis duration: 24689 ms

This is on an API 28 emulator. Is there a reason why it's still being reported?

In the logs, you see:

Leaks coming from the Android Framework or Google libraries.

and in the trace you pasted, at the top:

Known leak pattern: instance field android.app.assist.AssistStructure$ViewNodeText#mText
Description: AssistStructure (google assistant / autofill) holds on to text spannables on the screen. TextView.ChangeWatcher and android.widget.Editor end up in spans and typically hold on to the view hierarchy

This is still being reported because leakcanary cannot fix leaks for you.

Ah, so AndroidReferenceMatchers fills in details for _known_ leaks. It doesn't ignore them when they happen. I think I misunderstood it's purpose! Thanks.

Yep! What made you think it would ignore them / what do you think we could do to clarify this confusion for others as well?

I suppose my thinking was that if it is a known platform memory leak then there is no use in reporting it, as the app will likely not be able to fix the issue. Although in hindsight it may be able to do something else to mitigate/avoid it, so still worth showing.

Looking at https://square.github.io/leakcanary/api/shark-android/shark/-android-reference-matchers/ it's clearer now, but I only found this after I posted my first comment. This page explains the difference between known and ignored (false positives?) leaks and I think that makes general sense. I think this is more a case of RTFM on my side.

That said, let's say I have a particular case where we can't avoid this leak and it happens each time we go through a specific flow in the app, which ends up being an annoyance during development. Is there a way to ignore it? Is this actually even a good idea?

You can add your own custom "library leak patterns", and those could possibly match your own code. However LeakCanary has to analyze the heap to know what each leak is about, so you'll pay the cost anyway, it's only a classification difference. You're better off actually fixing that leak ;) . Even android framework leaks can be fixed with enough imagination and hackery.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

hidroh picture hidroh  ยท  3Comments

edgelv34 picture edgelv34  ยท  7Comments

msfjarvis picture msfjarvis  ยท  6Comments

devism picture devism  ยท  6Comments

pyricau picture pyricau  ยท  4Comments