-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Add special case to ignore Binder leaks #351
Conversation
Relevant issue: https://code.google.com/p/android/issues/detail?id=1797 |
@@ -176,6 +176,13 @@ private void visitRootObj(LeakNode node) { | |||
RootObj rootObj = (RootObj) node.instance; | |||
Instance child = rootObj.getReferredInstance(); | |||
|
|||
//We should ignore leaks where an android.os.Binder is the root of the leak. | |||
//When you bind and unbind from a Service, yhe OS will tend to keep a reference to the Binder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
little typo here. should be the
and not yhe
The referenced bug claims that the problems comes from the service process not being GCed. |
Correct.
The server process can't force the client process to do a GC, and it can't be notified when the client process has GC'ed either. Therefore the only way to not trigger false positives for LeakCanary notifications is to filter out instances of classes extending android.os.Binder as GC roots. |
I'll do a close review a bit later. |
Here's a branch where I modified the sample app to show the binder leaking: https://github.com/dandc87/leakcanary/compare/master...binder_leak_demo?expand=1 Just click the button and wait! |
Just to clarify: that branch you are linking to is a binder "real leak" that should be detected, correct? |
@@ -163,6 +163,20 @@ static boolean hasField(List<ClassInstance.FieldValue> values, String fieldName) | |||
return false; | |||
} | |||
|
|||
static boolean extendsFrom(Instance instance, String className) { | |||
if (instance == null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why check for null here, have you seen it happen?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It happened when I ran unit tests
I like it a lot overall, let's see if we can make it a bit more generic. |
Thanks Pierre for the review! |
Made changes based on your feedback @pyricau. I added |
The Android OS will retain a reference to `Binder` after a `Service` is unbound. This adds logic to ignore any paths where a `Binder` is at a root. We cannot simply add `Binder` with `ExcludedRef.Builder.clazz()` because there could be legitimate leaks where the `Binder` isn't the root.
import java.io.File; | ||
import java.net.URL; | ||
|
||
class TestUtil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
final
Thanks @dandc87 ! I'll take it from here, change one or two nits, and merge. |
* binder_leak: PR nits for #351 Add special case to ignore Binder leaks
@dandc87, it looks like 3d1f524 is resulting in false negatives, such as the case reported in #482. See d28f920 for an example test case. Revisiting the example you provided in https://github.com/dandc87/leakcanary/commit/5a293dbf8098c04adbfd4a2e13699e4a90bc0feb, it looks like the leak occurs because an anonymous subclass of Binder references the Service installed to the RefWatcher. Consider https://github.com/jrodbx/leakcanary/commit/c9dce97aedca03a4fee443330094e3b32175338d which doesn't result in a leak as mentioned in the original cited Google issue. Am I missing something? We can continue the dialog on this, but, in the meantime, I'll revert this commit since it's causing false negatives. |
The false-positive happens when the Binder has a reference to the Service, be that an explicit reference or implicit from being an anonymous sublcass. If you don't need the Service's context, you can refactor the 'leak' away. However, if you need access to the Service from the Binder, LeakCanary will report the Service as leaking because the Android system is holding onto the Binder instance after onDestroy() (but it will eventually get released and GC'd). You may want to just revert the changes made to AndroidExcludedRefs.java, I believe @pyricau did some cleanup after this merged, so I'm not sure how effective a full revert would be. |
* binder_leak: PR nits for square#351 Add special case to ignore Binder leaks
* binder_leak: PR nits for square#351 Add special case to ignore Binder leaks
The Android OS will retain a reference to
Binder
after aService
isunbound. This adds logic to ignore any paths where a
Binder
is at aroot. We cannot simply add
Binder
toExcludedRef
because there couldbe legitimate leaks where the
Binder
isn't the root.