main

square/leakcanary

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

WorkManagerHeapAnalyzer.kt

TLDR

This file contains the WorkManagerHeapAnalyzer object, which is an implementation of the EventListener interface. It listens for HeapDump events and starts a WorkManager worker to perform heap analysis.

Methods

There are no methods in this file.

Classes

There are no classes in this file.

package leakcanary

import androidx.work.OneTimeWorkRequest
import androidx.work.OutOfQuotaPolicy
import androidx.work.WorkManager
import leakcanary.EventListener.Event
import leakcanary.EventListener.Event.HeapDump
import leakcanary.internal.HeapAnalyzerWorker
import leakcanary.internal.HeapAnalyzerWorker.Companion.asWorkerInputData
import leakcanary.internal.InternalLeakCanary
import shark.SharkLog

/**
 * When receiving a [HeapDump] event, starts a WorkManager worker that performs heap analysis.
 */
object WorkManagerHeapAnalyzer : EventListener {

  internal val validWorkManagerInClasspath by lazy {
    try {
      Class.forName("androidx.work.WorkManager")
      // We need Data.Builder.putByteArray which was introduced in WorkManager 2.1.0.
      // https://github.com/square/leakcanary/issues/2310
      val dataBuilderClass = Class.forName("androidx.work.Data\$Builder")
      dataBuilderClass.declaredMethods.any { it.name == "putByteArray" }.apply {
        if (!this) {
          SharkLog.d { "Could not find androidx.work.Data\$Builder.putByteArray, WorkManager should be at least 2.1.0." }
        }
      }
    } catch (ignored: Throwable) {
      false
    }
  }

  // setExpedited() requires WorkManager 2.7.0+
  private val workManagerSupportsExpeditedRequests by lazy {
    try {
      Class.forName("androidx.work.OutOfQuotaPolicy")
      true
    } catch (ignored: Throwable) {
      false
    }
  }

  internal fun OneTimeWorkRequest.Builder.addExpeditedFlag() = apply {
    if (workManagerSupportsExpeditedRequests) {
      setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    }
  }

  override fun onEvent(event: Event) {
    if (event is HeapDump) {
      val heapAnalysisRequest = OneTimeWorkRequest.Builder(HeapAnalyzerWorker::class.java).apply {
        setInputData(event.asWorkerInputData())
        addExpeditedFlag()
      }.build()
      SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
      val application = InternalLeakCanary.application
      WorkManager.getInstance(application).enqueue(heapAnalysisRequest)
    }
  }
}