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

Crash during espresso tests #1336

Closed
emartynov opened this issue May 6, 2019 · 17 comments
Closed

Crash during espresso tests #1336

emartynov opened this issue May 6, 2019 · 17 comments
Milestone

Comments

@emartynov
Copy link

emartynov commented May 6, 2019

We have a crash:


05-06 11:09:32.164 | error | AndroidRuntime | FATAL EXCEPTION: IntentService[leakcanary.internal.AnalysisResultService]
-- | -- | -- | --
05-06 11:09:32.164 | error | AndroidRuntime | Process: com.yolt.mobile.aws, PID: 4762
05-06 11:09:32.164 | error | AndroidRuntime | java.util.NoSuchElementException: List is empty.
05-06 11:09:32.164 | error | AndroidRuntime | at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:194)
05-06 11:09:32.164 | error | AndroidRuntime | at leakcanary.internal.activity.db.LeakingInstanceTable.createGroupDescription(LeakingInstanceTable.kt:262)
05-06 11:09:32.164 | error | AndroidRuntime | at leakcanary.internal.activity.db.LeakingInstanceTable.insert(LeakingInstanceTable.kt:44)
05-06 11:09:32.164 | error | AndroidRuntime | at leakcanary.internal.activity.db.HeapAnalysisTable.insert(HeapAnalysisTable.kt:53)
05-06 11:09:32.164 | error | AndroidRuntime | at leakcanary.internal.AnalysisResultService.onHeapAnalyzed(AnalysisResultService.kt:91)
05-06 11:09:32.164 | error | AndroidRuntime | at leakcanary.internal.AnalysisResultService.onHandleIntentInForeground(AnalysisResultService.kt:70)
05-06 11:09:32.164 | error | AndroidRuntime | at leakcanary.internal.ForegroundService.onHandleIntent(ForegroundService.kt:56)
05-06 11:09:32.164 | error | AndroidRuntime | at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:68)
05-06 11:09:32.164 | error | AndroidRuntime | at android.os.Handler.dispatchMessage(Handler.java:102)
05-06 11:09:32.164 | error | AndroidRuntime | at android.os.Looper.loop(Looper.java:154)
05-06 11:09:32.164 | error | AndroidRuntime | at android.os.HandlerThread.run(HandlerThread.java:61)


It happened during our automated tests and I see from the log that LeakCanary detected a leak.

@emartynov
Copy link
Author

We are using the 2.0-alpha1 version.

@pyricau
Copy link
Member

pyricau commented May 6, 2019

Any chance you have a heap dump that could help me reproduce this?

This is happening because LeakCanary found 0 potential leak cause, which likely means the entire leak trace is considered reachable or unreachable, or there are inconsistencies. This is usually due to reachability inspectors reaching conflicting conclusions. I've added rules for alpha-2 that will correctl detect and solve conflicts, which means this shouldn't happen in the next release.

That being said I'd love to know what the inspectors are getting wrong, a heap dump would help

@pyricau pyricau added this to the 2.0 Next Release milestone May 6, 2019
@emartynov
Copy link
Author

I have a log of the leak, I don't have a dump. I can try to add saving of the dump, let me find how to do it.

@pyricau
Copy link
Member

pyricau commented May 7, 2019

One thing that's surprising to me: are you not using the instrumentation test listener? It looks like you're running normal LeakCanary in tests instead, which means the tests might be randomly freezing on heap dumps.

@emartynov
Copy link
Author

Good comment - I didn't add no-op dependency to instrumental tests. That is why "normal" LeakCanary also operates while running the UI tests. Let me do it and see what happens.

@pyricau
Copy link
Member

pyricau commented May 7, 2019

@pyricau
Copy link
Member

pyricau commented May 7, 2019

@emartynov
Copy link
Author

Oh wait, you're right and I actually have this already.

@emartynov
Copy link
Author

Then I don't know what could be the issue.

@pyricau
Copy link
Member

pyricau commented May 7, 2019

The crash shows that AnalysisResultService was started. AnalysisResultService should not start when FailTestOnLeakRunListener is set up: FailTestOnLeakRunListener#testRunStarted calls InstrumentationLeakDetector.Companion#updateConfig which configures LeakCanary to not dump the heap. Unless you're overriding that configuration somewhere else in the code?

@emartynov
Copy link
Author

Yes, we do, on the app start:

    fun install() {
        LeakCanary.config =
                LeakCanary.config.copy(excludedRefs = excludeSamsung(AndroidExcludedRefs.createAppDefaults()).build())
    }

    /**
     * LeakCanary is only excluding the SemClipboardManager and SemEmergencyManager until Android API 24,
     * but still occurs on Android API 25.
     */
    private fun excludeSamsung(builder: ExcludedRefs.Builder): ExcludedRefs.Builder {
        if ("samsung" == Build.MANUFACTURER && SDK_INT <= N_MR1) {
            builder.instanceField("com.samsung.android.content.clipboard.SemClipboardManager", "mContext")
                    .reason(
                            "SemClipboardManager is held in memory by an anonymous inner class implementation of " +
                                    "android.os.Binder, thereby leaking an activity context."
                    )
                    .instanceField("com.samsung.android.emergencymode.SemEmergencyManager", "mContext")
                    .reason("SemEmergencyManager is a static singleton that leaks a DecorContext.")
        }
        return builder
    }

@emartynov
Copy link
Author

But this also means that if I remove the listener from UI test I have somehow suppress LeakCanary from running in the UI tests since there is no-op. Let me add in our test runner config modification as well.

pyricau added a commit that referenced this issue May 7, 2019
* Combined leaking information from inspectors to solving conflicts while keeping all reasons
* Made reason from view leak inspector more obvious, and added label data about internals
* Moved reachability into LeakTraceElement
* Reachability renamed to LeakNodeStatus and leaking / not leaking
* ReachabilityInspector and Labeler are now functions with type aliases

Related to #1336: should fix the crash, though it's still unclear why AppCompatButton was a gc root there.
pyricau added a commit that referenced this issue May 7, 2019
* Combined leaking information from inspectors to solving conflicts while keeping all reasons
* Made reason from view leak inspector more obvious, and added label data about internals
* Moved reachability into LeakTraceElement
* Reachability renamed to LeakNodeStatus and leaking / not leaking
* ReachabilityInspector and Labeler are now functions with type aliases

Related to #1336: should fix the crash, though it's still unclear why AppCompatButton was a gc root there.
@ber4444
Copy link

ber4444 commented May 13, 2019

I also have CI builds randomly fail because of leak canary (latest alpha) breaking Espresso tests. E.g.

java.util.NoSuchElementException: List is empty.
FATAL EXCEPTION: IntentService[leakcanary.internal.AnalysisResultService]
Process: com.blah.activities.debug, PID: 7940
java.util.NoSuchElementException: List is empty.
	at kotlin.collections.CollectionsKt___CollectionsKt.first(_Collections.kt:194)
	at leakcanary.internal.activity.db.LeakingInstanceTable.createGroupDescription(LeakingInstanceTable.kt:262)
	at leakcanary.internal.activity.db.LeakingInstanceTable.insert(LeakingInstanceTable.kt:44)
	at leakcanary.internal.activity.db.HeapAnalysisTable.insert(HeapAnalysisTable.kt:53)
	at leakcanary.internal.AnalysisResultService.onHeapAnalyzed(AnalysisResultService.kt:91)
	at leakcanary.internal.AnalysisResultService.onHandleIntentInForeground(AnalysisResultService.kt:70)
	at leakcanary.internal.ForegroundService.onHandleIntent(ForegroundService.kt:56)
	at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:76)
	at android.os.Handler.dispatchMessage(Handler.java:106)
	at android.os.Looper.loop(Looper.java:193)
	at android.os.HandlerThread.run(HandlerThread.java:65)

Is there a way I could disable leak canary 2.x for tests now that no-op is gone?

@emartynov
Copy link
Author

If you have own test runner then you can try next code:

    override fun onStart() {
        // disable LeakCanary in UI tests here since we don't have no-op artifact anymore
        LeakCanary.config = LeakCanary.config.copy(dumpHeap = false, computeRetainedHeapSize = false)

        // carry on
        super.onStart()
    }

@ber4444
Copy link

ber4444 commented May 13, 2019

Sorry, where should I put this code? You wrote a custom AndroidJUnitRunner?

@emartynov
Copy link
Author

Sound like you don't have it.

Then you should add new class to espresso test:

class <My>InstrumentationRunner : AndroidJUnitRunner() 

Then you should also define it in your build.gradle:

android {
  ...
  defaultConfig {
    ...
    testInstrumentationRunner 'com.<yourpackge>.<My>InstrumentationRunner'
  }
}

And then, in this runner, you should override onStart method.

@pyricau
Copy link
Member

pyricau commented May 21, 2019

This should be fixed in the next release, let me know if not.

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

No branches or pull requests

3 participants