Retryable.Result ensureGone(final KeyedWeakReference reference, finallong watchStartNanoTime){ long gcStartNanoTime = System.nanoTime(); long watchDurationMs = NANOSECONDS.toMillis(gcStartNanoTime - watchStartNanoTime);
removeWeaklyReachableReferences();
if (debuggerControl.isDebuggerAttached()) { // The debugger can create false leaks. return RETRY; } if (gone(reference)) { return DONE; } gcTrigger.runGc(); removeWeaklyReachableReferences(); if (!gone(reference)) { long startDumpHeap = System.nanoTime(); long gcDurationMs = NANOSECONDS.toMillis(startDumpHeap - gcStartNanoTime);
File heapDumpFile = heapDumper.dumpHeap(); if (heapDumpFile == RETRY_LATER) { // Could not dump the heap. return RETRY; } long heapDumpDurationMs = NANOSECONDS.toMillis(System.nanoTime() - startDumpHeap); heapdumpListener.analyze( new HeapDump(heapDumpFile, reference.key, reference.name, excludedRefs, watchDurationMs, gcDurationMs, heapDumpDurationMs)); } return DONE; }
/** * {@link WatchExecutor} suitable for watching Android reference leaks. This executor waits for the * main thread to be idle then posts to a serial background thread with a delay of * {@link R.integer#leak_canary_watch_delay_millis} seconds. */ publicfinalclassAndroidWatchExecutorimplementsWatchExecutor{
voidwaitForIdle(final Retryable retryable, finalint failedAttempts){ // This needs to be called from the main thread. Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() { @OverridepublicbooleanqueueIdle(){ postToBackgroundWithDelay(retryable, failedAttempts); returnfalse; } }); }