main

square/leakcanary

Last updated at: 29/12/2023 09:38

KeyedWeakReferenceFinder.kt

TLDR

This file defines an object called KeyedWeakReferenceFinder that implements the LeakingObjectFinder interface. It contains a method called findLeakingObjectIds which finds all objects tracked by a KeyedWeakReference and returns their IDs. It also includes a method called heapDumpUptimeMillis which retrieves the uptime in milliseconds when the heap dump was taken. Additionally, there is an internal method called findKeyedWeakReferences which finds all instances of KeyedWeakReferenceMirror in the heap graph.

Methods

findLeakingObjectIds

This method finds all objects in the heap graph that are tracked by a KeyedWeakReference. It filters the KeyedWeakReference instances to select those that have a non-null referent and are retained. It then maps these instances to their values and returns a set of the resulting object IDs.

heapDumpUptimeMillis

This method retrieves the uptime in milliseconds when the heap dump was taken. It checks if the leakcanary.KeyedWeakReference.heapDumpUptimeMillis field exists in the heap graph. If it does, the value of this field is returned. Otherwise, null is returned. If the field is not found, a log message is printed.

findKeyedWeakReferences

This internal method finds and returns a list of KeyedWeakReferenceMirror instances in the heap graph. It first checks if the instances have already been added to the context using a predefined key. If they have not been added, it finds the class IDs for the KeyedWeakReference class and a legacy KeyedWeakReference class. It retrieves the heap dump uptime milliseconds using the heapDumpUptimeMillis method. It then filters the instances in the heap graph to select those that belong to either the KeyedWeakReference class or the legacy KeyedWeakReference class. These instances are mapped to KeyedWeakReferenceMirror instances using the fromInstance method and added to the context. The added instances are returned as the result.

package shark

import shark.ObjectInspectors.KEYED_WEAK_REFERENCE
import shark.internal.KeyedWeakReferenceMirror

/**
 * Finds all objects tracked by a KeyedWeakReference, ie all objects that were passed to
 * ObjectWatcher.watch.
 */
object KeyedWeakReferenceFinder : LeakingObjectFinder {

  override fun findLeakingObjectIds(graph: HeapGraph): Set<Long> =
    findKeyedWeakReferences(graph)
      .filter { it.hasReferent && it.isRetained }
      .map { it.referent.value }
      .toSet()

  fun heapDumpUptimeMillis(graph: HeapGraph): Long? {
    return graph.context.getOrPut("heapDumpUptimeMillis") {
      val keyedWeakReferenceClass = graph.findClassByName("leakcanary.KeyedWeakReference")
      val heapDumpUptimeMillis = if (keyedWeakReferenceClass == null) {
        null
      } else {
        keyedWeakReferenceClass["heapDumpUptimeMillis"]?.value?.asLong
      }
      if (heapDumpUptimeMillis == null) {
        SharkLog.d {
          "leakcanary.KeyedWeakReference.heapDumpUptimeMillis field not found"
        }
      }
      heapDumpUptimeMillis
    }
  }

  internal fun findKeyedWeakReferences(graph: HeapGraph): List<KeyedWeakReferenceMirror> {
    return graph.context.getOrPut(KEYED_WEAK_REFERENCE.name) {
      val keyedWeakReferenceClass = graph.findClassByName("leakcanary.KeyedWeakReference")

      val keyedWeakReferenceClassId = keyedWeakReferenceClass?.objectId ?: 0
      val legacyKeyedWeakReferenceClassId =
        graph.findClassByName("com.squareup.leakcanary.KeyedWeakReference")?.objectId ?: 0

      val heapDumpUptimeMillis = heapDumpUptimeMillis(graph)

      val addedToContext: List<KeyedWeakReferenceMirror> = graph.instances
        .filter { instance ->
          instance.instanceClassId == keyedWeakReferenceClassId || instance.instanceClassId == legacyKeyedWeakReferenceClassId
        }
        .map {
          KeyedWeakReferenceMirror.fromInstance(
            it, heapDumpUptimeMillis
          )
        }
        .toList()
      graph.context[KEYED_WEAK_REFERENCE.name] = addedToContext
      addedToContext
    }
  }
}