square / leakcanary

A memory leak detection library for Android.
https://square.github.io/leakcanary
Apache License 2.0
29.44k stars 3.97k forks source link

LeakCanary 3 #2511

Open pyricau opened 1 year ago

pyricau commented 1 year ago

What to expect.

Changes to configuration

Startup

Analysis now performed in LeakCanary app

App APIs

New features

Notifications

Security

Analytics

Proguard / R8

Installing / upgrading the app

App internals

Dependency updates

Removed old LeakCanary activity

Internals and APIs

Compose Desktop / Intellij Plugin

New feature

pyricau commented 1 year ago

Conversation on coroutines / flow for LeakTracer with Bill:

package shark

import kotlin.coroutines.CoroutineContext
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.SharedFlow
import shark.LeakTracer.TraceObjectsEvent.StartedBuildingLeakTraces

fun interface LeakTracer {

  // TODO What should we do about exceptions here? union error or exception?
  fun traceObjects(objectIds: Set<Long>): LeaksAndUnreachableObjects

  // main safety
  suspend fun traceObjectsSuspending(
    // coroutineContext: CoroutineDispatcher, // this doesn't allow me to say, "use my existing dispatcher!"
    coroutineContext: CoroutineContext, // constructor DI is probably a good approach for this
    // Be careful with context you call this on!
    //     * events callback should be called on the same CoroutineContext as traceObjectsSuspending
    // Also: make sure and honor exception contracts! (e.g. if `events` throws,
    // `traceObjectSuspending` should throw that exeption)
    //
    // Flows get the above invariants right, so if you build on top of them you should be good
    events: (TraceObjectsEvent)->Unit
  ): LeaksAndUnreachableObjects

  data class TraceObjectsAsyncProcess(
    val job: Job,
    val events: SharedFlow<TraceObjectsEvent>,
    val result: Deferred<LeaksAndUnreachableObjects>,
  )

  fun traceObjectsAsync(coroutineScope: CoroutineScope, objectIds: Set<Long>): TraceObjectsAsyncProcess

  suspend fun heapGraph(block: suspend HeapGraph.()->Unit)
  suspend fun blah () {

    coroutineScope {
      val result: Deferred<Int> = async {
        1
      }
    }
    val result = traceObjectsSuspending {
      // event handling here
    }
  }
  // Flow? AndroidX Biometrics API
  //

  sealed interface TraceObjectsEvent {
    object StartedBuildingLeakTraces :  TraceObjectsEvent
    object StartedInspectingObjects :  TraceObjectsEvent
    object StartedComputingNativeRetainedSize:  TraceObjectsEvent
    object StartedComputingJavaHeapRetainedSize:  TraceObjectsEvent
  }

  fun traceObjectsFlow(objectIds: Set<Long>) : Flow<TraceObjectsEvent>

  // what this ^^^^ is actually doing

  suspend fun myFunction(callback: suspend (TraceObjectsEvent)->Unit) {
    while (true) {
      callback(StartedBuildingLeakTraces)
    }

  }

  fun whatItIsDoing() = object : Flow<TraceObjectsEvent> {
    override suspend fun collect(collector: FlowCollector<TraceObjectsEvent>) {
      TODO("Not yet implemented")
    }
  }

  fun interface Factory {
    fun createFor(heapGraph: HeapGraph): LeakTracer
  }
}
pyricau commented 6 months ago

A few next steps: