Open pyricau opened 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
}
}
A few next steps:
ClassReferenceReader
to have a customizable list of static JVM fields that are ignored on all classesJavaLocalAllowListPattern
ReferencePattern ("local variable on thread that is not one of $threadNames"
). Or, instead, figure out a general way to handle all references and reject some as needed
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