1 package leakcanary 2 3 import androidx.work.OneTimeWorkRequest 4 import androidx.work.OutOfQuotaPolicy 5 import androidx.work.WorkManager 6 import leakcanary.EventListener.Event 7 import leakcanary.EventListener.Event.HeapDump 8 import leakcanary.internal.HeapAnalyzerWorker 9 import leakcanary.internal.HeapAnalyzerWorker.Companion.asWorkerInputData 10 import leakcanary.internal.InternalLeakCanary 11 import shark.SharkLog 12 13 /** 14 * When receiving a [HeapDump] event, starts a WorkManager worker that performs heap analysis. 15 */ 16 object WorkManagerHeapAnalyzer : EventListener { 17 <lambda>null18 internal val validWorkManagerInClasspath by lazy { 19 try { 20 Class.forName("androidx.work.WorkManager") 21 // We need Data.Builder.putByteArray which was introduced in WorkManager 2.1.0. 22 // https://github.com/square/leakcanary/issues/2310 23 val dataBuilderClass = Class.forName("androidx.work.Data\$Builder") 24 dataBuilderClass.declaredMethods.any { it.name == "putByteArray" }.apply { 25 if (!this) { 26 SharkLog.d { "Could not find androidx.work.Data\$Builder.putByteArray, WorkManager should be at least 2.1.0." } 27 } 28 } 29 } catch (ignored: Throwable) { 30 false 31 } 32 } 33 34 // setExpedited() requires WorkManager 2.7.0+ <lambda>null35 private val workManagerSupportsExpeditedRequests by lazy { 36 try { 37 Class.forName("androidx.work.OutOfQuotaPolicy") 38 true 39 } catch (ignored: Throwable) { 40 false 41 } 42 } 43 addExpeditedFlagnull44 internal fun OneTimeWorkRequest.Builder.addExpeditedFlag() = apply { 45 if (workManagerSupportsExpeditedRequests) { 46 setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST) 47 } 48 } 49 onEventnull50 override fun onEvent(event: Event) { 51 if (event is HeapDump) { 52 val heapAnalysisRequest = OneTimeWorkRequest.Builder(HeapAnalyzerWorker::class.java).apply { 53 setInputData(event.asWorkerInputData()) 54 addExpeditedFlag() 55 }.build() 56 SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" } 57 val application = InternalLeakCanary.application 58 WorkManager.getInstance(application).enqueue(heapAnalysisRequest) 59 } 60 } 61 } 62