1 package leakcanary
2 
3 import androidx.work.Data
4 import androidx.work.OneTimeWorkRequest
5 import androidx.work.WorkManager
6 import androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_CLASS_NAME
7 import androidx.work.multiprocess.RemoteListenableWorker.ARGUMENT_PACKAGE_NAME
8 import leakcanary.EventListener.Event
9 import leakcanary.EventListener.Event.HeapDump
10 import leakcanary.internal.HeapAnalyzerWorker.Companion.asWorkerInputData
11 import leakcanary.internal.InternalLeakCanary
12 import leakcanary.internal.RemoteHeapAnalyzerWorker
13 import shark.SharkLog
14 
15 /**
16  * When receiving a [HeapDump] event, starts a WorkManager worker that performs heap analysis in
17  * a dedicated :leakcanary process
18  */
19 object RemoteWorkManagerHeapAnalyzer : EventListener {
20 
21   private const val REMOTE_SERVICE_CLASS_NAME = "leakcanary.internal.RemoteLeakCanaryWorkerService"
22 
<lambda>null23   internal val remoteLeakCanaryServiceInClasspath by lazy {
24     try {
25       Class.forName(REMOTE_SERVICE_CLASS_NAME)
26       true
27     } catch (ignored: Throwable) {
28       false
29     }
30   }
31 
onEventnull32   override fun onEvent(event: Event) {
33     if (event is HeapDump) {
34       val application = InternalLeakCanary.application
35       val heapAnalysisRequest =
36         OneTimeWorkRequest.Builder(RemoteHeapAnalyzerWorker::class.java).apply {
37           val dataBuilder = Data.Builder()
38             .putString(ARGUMENT_PACKAGE_NAME, application.packageName)
39             .putString(ARGUMENT_CLASS_NAME, REMOTE_SERVICE_CLASS_NAME)
40           setInputData(event.asWorkerInputData(dataBuilder))
41           with(WorkManagerHeapAnalyzer) {
42             addExpeditedFlag()
43           }
44         }.build()
45       SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
46       val workManager = WorkManager.getInstance(application)
47       workManager.enqueue(heapAnalysisRequest)
48     }
49   }
50 }
51