Skip to content

Commit

Permalink
Reverting API breaking changes from alpha 1
Browse files Browse the repository at this point in the history
  • Loading branch information
pyricau committed May 1, 2024
1 parent 7821816 commit 6a8a197
Show file tree
Hide file tree
Showing 10 changed files with 100 additions and 43 deletions.
1 change: 1 addition & 0 deletions docs/changelog.md
Expand Up @@ -8,6 +8,7 @@ Please thank our [contributors](https://github.com/square/leakcanary/graphs/cont
### Heap Growth

* Deleted the `shark-heap-growth` artifact, the code has been merged into the `shark*` and `leakcanary*` modules.
* Undo of breaking API changes that were introduced in alpha 1. The goal is to make the upgrade seamless. Please file an issue if you find an API breaking change from a 2.x release.
* New `leakcanary-core` module that includes runtime leak detection utilities that aren't Android specific.
* Optimization: for known data structures that don't reference the rest of the graph beyond the references we
known about, we explore them locally at once and stop enqueuing their internals, which reduces the memory
Expand Down
@@ -1,5 +1,6 @@
public final class leakcanary/ActivityWatcher : leakcanary/InstallableWatcher {
public fun <init> (Landroid/app/Application;Lleakcanary/DeletableObjectReporter;)V
public fun <init> (Landroid/app/Application;Lleakcanary/ReachabilityWatcher;)V
public fun install ()V
public fun uninstall ()V
}
Expand Down Expand Up @@ -33,15 +34,26 @@ public abstract interface class leakcanary/InstallableWatcher {
}

public final class leakcanary/RootViewWatcher : leakcanary/InstallableWatcher {
public fun <init> (Lleakcanary/DeletableObjectReporter;Z)V
public synthetic fun <init> (Lleakcanary/DeletableObjectReporter;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lleakcanary/DeletableObjectReporter;Lleakcanary/RootViewWatcher$Filter;)V
public synthetic fun <init> (Lleakcanary/DeletableObjectReporter;Lleakcanary/RootViewWatcher$Filter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lleakcanary/ReachabilityWatcher;)V
public fun install ()V
public fun uninstall ()V
}

public abstract interface class leakcanary/RootViewWatcher$Filter {
public abstract fun shouldExpectDeletionOnDetached (Landroid/view/View;)Z
}

public final class leakcanary/RootViewWatcher$WindowTypeFilter : leakcanary/RootViewWatcher$Filter {
public fun <init> (Z)V
public fun shouldExpectDeletionOnDetached (Landroid/view/View;)Z
}

public final class leakcanary/ServiceWatcher : leakcanary/InstallableWatcher {
public static final field Companion Lleakcanary/ServiceWatcher$Companion;
public fun <init> (Lleakcanary/DeletableObjectReporter;)V
public fun <init> (Lleakcanary/ReachabilityWatcher;)V
public fun install ()V
public fun uninstall ()V
}
Expand Down
Expand Up @@ -13,6 +13,12 @@ class ActivityWatcher(
private val deletableObjectReporter: DeletableObjectReporter
) : InstallableWatcher {

// Kept for backward compatibility.
constructor(
application: Application,
reachabilityWatcher: ReachabilityWatcher
) : this(application, reachabilityWatcher.asDeletableObjectReporter())

private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
Expand Down
Expand Up @@ -4,6 +4,7 @@ import android.app.Application
import android.os.SystemClock
import com.squareup.leakcanary.objectwatcher.core.R
import java.util.concurrent.TimeUnit
import leakcanary.RootViewWatcher.WindowTypeFilter
import leakcanary.internal.LeakCanaryDelegate
import leakcanary.internal.friendly.checkMainThread
import leakcanary.internal.friendly.mainHandler
Expand Down Expand Up @@ -127,7 +128,7 @@ object AppWatcher {
*/
fun appDefaultWatchers(
application: Application,
deletableObjectReporter: DeletableObjectReporter = objectWatcher
deletableObjectReporter: DeletableObjectReporter = objectWatcher.asDeletableObjectReporter()
): List<InstallableWatcher> {
// Use app context resources to avoid NotFoundException
// https://github.com/square/leakcanary/issues/2137
Expand All @@ -136,7 +137,7 @@ object AppWatcher {
return listOf(
ActivityWatcher(application, deletableObjectReporter),
FragmentAndViewModelWatcher(application, deletableObjectReporter),
RootViewWatcher(deletableObjectReporter, watchDismissedDialogs),
RootViewWatcher(deletableObjectReporter, WindowTypeFilter(watchDismissedDialogs)),
ServiceWatcher(deletableObjectReporter)
)
}
Expand Down
Expand Up @@ -37,25 +37,39 @@ import leakcanary.internal.friendly.mainHandler
*/
class RootViewWatcher(
private val deletableObjectReporter: DeletableObjectReporter,
private val watchDismissedDialogs: Boolean = false
private val rootViewFilter: Filter = WindowTypeFilter(watchDismissedDialogs = false)
) : InstallableWatcher {

private val listener = OnRootViewAddedListener { rootView ->
val trackDetached = when(rootView.windowType) {
PHONE_WINDOW -> {
when (rootView.phoneWindow?.callback?.wrappedCallback) {
// Activities are already tracked by ActivityWatcher
is Activity -> false
is Dialog -> watchDismissedDialogs
// Probably a DreamService
else -> true
fun interface Filter {
fun shouldExpectDeletionOnDetached(rootView: View): Boolean
}

class WindowTypeFilter(private val watchDismissedDialogs: Boolean) : Filter {
override fun shouldExpectDeletionOnDetached(rootView: View): Boolean {
return when (rootView.windowType) {
PHONE_WINDOW -> {
when (rootView.phoneWindow?.callback?.wrappedCallback) {
// Activities are already tracked by ActivityWatcher
is Activity -> false
is Dialog -> watchDismissedDialogs
// Probably a DreamService
else -> true
}
}
// Android widgets keep detached popup window instances around.
POPUP_WINDOW -> false
TOOLTIP, TOAST, UNKNOWN -> true
}
// Android widgets keep detached popup window instances around.
POPUP_WINDOW -> false
TOOLTIP, TOAST, UNKNOWN -> true
}
if (trackDetached) {
}

// Kept for backward compatibility.
constructor(reachabilityWatcher: ReachabilityWatcher) : this(
deletableObjectReporter = reachabilityWatcher.asDeletableObjectReporter()
)

private val listener = OnRootViewAddedListener { rootView ->
if (rootViewFilter.shouldExpectDeletionOnDetached(rootView)) {
rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {

val watchDetachedView = Runnable {
Expand Down
Expand Up @@ -5,19 +5,25 @@ import android.app.Service
import android.os.Build
import android.os.Handler
import android.os.IBinder
import leakcanary.internal.friendly.checkMainThread
import shark.SharkLog
import java.lang.ref.WeakReference
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Proxy
import java.util.WeakHashMap
import leakcanary.internal.friendly.checkMainThread
import shark.SharkLog

/**
* Expects services to become weakly reachable soon after they receive the [Service.onDestroy]
* callback.
*/
@SuppressLint("PrivateApi")
class ServiceWatcher(private val deletableObjectReporter: DeletableObjectReporter) : InstallableWatcher {
class ServiceWatcher(private val deletableObjectReporter: DeletableObjectReporter) :
InstallableWatcher {

// Kept for backward compatibility.
constructor(reachabilityWatcher: ReachabilityWatcher) : this(
reachabilityWatcher.asDeletableObjectReporter()
)

private val servicesToBeDestroyed = WeakHashMap<IBinder, WeakReference<Service>>()

Expand Down
8 changes: 4 additions & 4 deletions object-watcher/object-watcher/api/object-watcher.api
Expand Up @@ -54,11 +54,11 @@ public final class leakcanary/ObjectWatcher : leakcanary/ReachabilityWatcher, le
public fun <init> (Lleakcanary/Clock;Ljava/util/concurrent/Executor;Lkotlin/jvm/functions/Function0;)V
public synthetic fun <init> (Lleakcanary/Clock;Ljava/util/concurrent/Executor;Lkotlin/jvm/functions/Function0;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun addOnObjectRetainedListener (Lleakcanary/OnObjectRetainedListener;)V
public fun asDeletableObjectReporter ()Lleakcanary/DeletableObjectReporter;
public fun clearAllObjectsTracked ()V
public fun clearObjectsTrackedBefore-LRDsOJo (J)V
public final fun clearObjectsWatchedBefore (J)V
public final fun clearWatchedObjects ()V
public fun expectDeletionFor (Ljava/lang/Object;Ljava/lang/String;)Lleakcanary/TrackedObjectReachability;
public fun expectWeaklyReachable (Ljava/lang/Object;Ljava/lang/String;)V
public fun getHasRetainedObjects ()Z
public fun getHasTrackedObjects ()Z
Expand All @@ -75,13 +75,13 @@ public abstract interface class leakcanary/OnObjectRetainedListener {
public abstract fun onObjectRetained ()V
}

public abstract interface class leakcanary/ReachabilityWatcher : leakcanary/DeletableObjectReporter {
public abstract fun expectDeletionFor (Ljava/lang/Object;Ljava/lang/String;)Lleakcanary/TrackedObjectReachability;
public abstract interface class leakcanary/ReachabilityWatcher {
public abstract fun asDeletableObjectReporter ()Lleakcanary/DeletableObjectReporter;
public abstract fun expectWeaklyReachable (Ljava/lang/Object;Ljava/lang/String;)V
}

public final class leakcanary/ReachabilityWatcher$DefaultImpls {
public static fun expectDeletionFor (Lleakcanary/ReachabilityWatcher;Ljava/lang/Object;Ljava/lang/String;)Lleakcanary/TrackedObjectReachability;
public static fun asDeletableObjectReporter (Lleakcanary/ReachabilityWatcher;)Lleakcanary/DeletableObjectReporter;
}

public final class leakcanary/ReferenceQueueRetainedObjectTracker : leakcanary/RetainedObjectTracker, leakcanary/TriggeredDeletableObjectReporter {
Expand Down
Expand Up @@ -16,5 +16,26 @@ fun interface DeletableObjectReporter {
fun expectDeletionFor(
target: Any,
reason: String
) : TrackedObjectReachability
): TrackedObjectReachability
}

/**
* Creates a wrapper around [DeletableObjectReporter] that will run any instance of [T] by [apply]
* to decide whether to forward to [DeletableObjectReporter.expectDeletionFor] calls. Objects
* that do not extend [T] will always be forwarded.
*/
inline fun <reified T> DeletableObjectReporter.filteringInstances(
crossinline apply: (T) -> Boolean
): DeletableObjectReporter {
val delegate = this
return DeletableObjectReporter { target, reason ->
if (target !is T || apply(target)) {
delegate.expectDeletionFor(target, reason)
} else object : TrackedObjectReachability {
override val isStronglyReachable: Boolean
get() = false
override val isRetained: Boolean
get() = false
}
}
}
@@ -1,7 +1,7 @@
package leakcanary

@Deprecated("Use DeletableObjectReporter instead", ReplaceWith("DeletableObjectReporter"))
fun interface ReachabilityWatcher : DeletableObjectReporter {
fun interface ReachabilityWatcher {

/**
* Expects the provided [watchedObject] to become weakly reachable soon. If not,
Expand All @@ -12,20 +12,16 @@ fun interface ReachabilityWatcher : DeletableObjectReporter {
description: String
)

/**
* This method exists for backward-compatibility purposes and as such is unable to return
* an accurate [TrackedObjectReachability] implementation.
*/
override fun expectDeletionFor(
target: Any,
reason: String
): TrackedObjectReachability {
expectWeaklyReachable(target, reason)
return object : TrackedObjectReachability {
override val isStronglyReachable: Boolean
get() = error("Use a non deprecated DeletableObjectReporter implementation instead")
override val isRetained: Boolean
get() = error("Use a non deprecated DeletableObjectReporter implementation instead")
fun asDeletableObjectReporter(): DeletableObjectReporter =
DeletableObjectReporter { target, reason ->
expectWeaklyReachable(target, reason)
// This exists for backward-compatibility purposes and as such is unable to return
// an accurate [TrackedObjectReachability] implementation.
object : TrackedObjectReachability {
override val isStronglyReachable: Boolean
get() = error("Use a non deprecated DeletableObjectReporter implementation instead")
override val isRetained: Boolean
get() = error("Use a non deprecated DeletableObjectReporter implementation instead")
}
}
}
}
Expand Up @@ -75,7 +75,7 @@ class ExampleSetup {
// Or maybe just delete support for support lib.
FragmentAndViewModelWatcher(application, deletableObjectReporter),
// TODO should configure this
RootViewWatcher(deletableObjectReporter, false),
RootViewWatcher(deletableObjectReporter),
ServiceWatcher(deletableObjectReporter)
)

Expand Down

0 comments on commit 6a8a197

Please sign in to comment.