android LeakCanary 2.7 启动流程 详解
LeakCanary 2.7 启动监听流程(基于appDefaultWatchers源码)
以你给出的appDefaultWatchers()源码为切入点,LeakCanary 2.7 的启动流程可以拆解为"自动初始化 → 装配 Watchers → 生命周期 Hook → 引用追踪 → Heap Dump"五个阶段。下面按源码层级逐步展开。
一、架构设计:从appDefaultWatchers看 2.7 的接口化改造
你贴出的源码是 LeakCanary 2.6+ 引入的核心 API,它体现了 2.x 的模块化设计哲学:
kotlin
fun appDefaultWatchers( application: Application, reachabilityWatcher: ReachabilityWatcher = objectWatcher ): List<InstallableWatcher> { return listOf( ActivityWatcher(application, reachabilityWatcher), FragmentAndViewModelWatcher(application, reachabilityWatcher), RootViewWatcher(reachabilityWatcher), ServiceWatcher(reachabilityWatcher) ) }关键设计点:
| 设计 | 说明 |
|---|---|
ReachabilityWatcher接口 | 2.6+ 引入的 SAM 接口,由ObjectWatcher实现。四个 Watcher 不直接依赖ObjectWatcher,而是依赖接口,解耦了"监听触发"与"引用追踪" |
InstallableWatcher接口 | 每个 Watcher 实现install()方法,负责注册系统回调或反射 Hook。manualInstall()只需遍历调用it.install()即可统一注册 |
共享objectWatcher | 四个 Watcher 共享同一个AppWatcher.objectWatcher实例,确保所有被追踪对象都在同一个watchedObjectsMap 中管理 |
二、自动初始化链路:ContentProvider 触发
leakcanary-android:2.7依赖的AndroidManifest.xml中注册了自动初始化入口:
xml
<provider android:name="leakcanary.internal.AppWatcherInstaller$MainProcess" android:authorities="${applicationId}.leakcanary-installer" android:enabled="@bool/leak_canary_watcher_auto_install" android:exported="false" />对应的AppWatcherInstaller源码:
kotlin
internal sealed class AppWatcherInstaller : ContentProvider() { internal class MainProcess : AppWatcherInstaller() override fun onCreate(): Boolean { val application = context!!.applicationContext as Application AppWatcher.manualInstall(application) // 默认调用,watchersToInstall = appDefaultWatchers(application) return true } }执行时序:Application.attachBaseContext()→ContentProvider.onCreate()→Application.onCreate()。LeakCanary 在Application.onCreate()之前就已经完成所有 Watcher 的注册。
三、manualInstall内部执行流程
kotlin
@JvmOverloads fun manualInstall( application: Application, retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5), watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application) ) { checkMainThread() // ① 必须在主线程 if (isInstalled) { // ② 防重入保护 throw IllegalStateException("AppWatcher already installed") } // ③ 加载 LeakCanary 分析引擎(如果 classpath 中存在) LeakCanaryDelegate.loadLeakCanary(application) // ④ 遍历安装所有 Watcher watchersToInstall.forEach { it.install() } }关键步骤解析:
LeakCanaryDelegate.loadLeakCanary(application):通过反射查找InternalLeakCanary类并实例化,将AppWatcher.objectWatcher注册为OnObjectRetainedListener。这样当ObjectWatcher检测到 retained 对象时,能触发后续的 heap dump。watchersToInstall.forEach { it.install() }:调用你列出的四个 Watcher 的install()方法,分别向系统注册生命周期监听。
四、四大 Watcher 的注册与实现细节
1.ActivityWatcher
kotlin
internal class ActivityWatcher( private val application: Application, private val reachabilityWatcher: ReachabilityWatcher ) : InstallableWatcher { private val lifecycleCallbacks = object : Application.ActivityLifecycleCallbacks { override fun onActivityDestroyed(activity: Activity) { reachabilityWatcher.expectWeaklyReachable( activity, "Activity received onDestroy() callback" ) } // 其他生命周期方法为空实现 } override fun install() { application.registerActivityLifecycleCallbacks(lifecycleCallbacks) } }机制:通过Application.registerActivityLifecycleCallbacks()监听所有 Activity 的onDestroy(),销毁时立即将 Activity 实例交给ObjectWatcher追踪。
2.FragmentAndViewModelWatcher
kotlin
internal class FragmentAndViewModelWatcher( private val application: Application, private val reachabilityWatcher: ReachabilityWatcher ) : InstallableWatcher { override fun install() { application.registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks { override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { // 注册 Fragment 生命周期回调 (activity as? FragmentActivity)?.supportFragmentManager ?.registerFragmentLifecycleCallbacks(fragmentCallbacks, true) } }) } private val fragmentCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() { override fun onFragmentDestroyed(fm: FragmentManager, fragment: Fragment) { reachabilityWatcher.expectWeaklyReachable(fragment, "Fragment destroyed") // 同时追踪 Fragment 的 View fragment.view?.let { view -> reachabilityWatcher.expectWeaklyReachable(view, "Fragment view destroyed") } } override fun onFragmentViewDestroyed(fm: FragmentManager, fragment: Fragment) { // ViewModel 监听通过 ViewModelStore 实现 watchViewModel(fragment) } } }机制:
利用
FragmentManager.FragmentLifecycleCallbacks监听Fragment.onDestroy()Fragment 的 View 和 ViewModel 分别独立追踪
ViewModel 通过
ViewModelStore的onCleared()回调触发追踪
3.RootViewWatcher(2.7 改进版)
kotlin
internal class RootViewWatcher( private val reachabilityWatcher: ReachabilityWatcher ) : InstallableWatcher { override fun install() { // 2.7 使用 Curtains 库替代直接注册 OnAttachStateChangeListener Curtains.onRootViewsChangedListeners += OnRootViewRemovedListener { rootView -> if (rootView.windowType == WindowType.PHONE_WINDOW) { // 2.7 默认忽略 PopupWindow 和 Dialog 的 root view // 可通过资源 bool leak_canary_watcher_watch_dismissed_dialogs 开启 if (rootView.watchDismissedDialogs || rootView !is DialogRootView) { reachabilityWatcher.expectWeaklyReachable( rootView, "View detached from window" ) } } } } }2.7 关键改进:引入Curtains库来统一监听 Window/RootView 的添加和移除,解决了 2.6 中误报 PopupWindow/Dialog 的问题。
默认行为:
✅ 继续检测 Toast 的 root view 泄漏
❌ 忽略
PopupWindow创建的 root view❌ 忽略
Dialog创建的 root view(可通过leak_canary_watcher_watch_dismissed_dialogs资源布尔值开启)
4.ServiceWatcher
kotlin
internal class ServiceWatcher(private val reachabilityWatcher: ReachabilityWatcher) : InstallableWatcher { override fun install() { // Android SDK 没有 Service 生命周期公开 API,通过反射 Hook IActivityManager val activityThreadClass = Class.forName("android.app.ActivityThread") val activityThread = activityThreadClass.getMethod("currentActivityThread").invoke(null) // Hook AMS 的 serviceDoneExecuting 方法 val iActivityManager = ActivityManager.getService() val proxy = Proxy.newProxyInstance( iActivityManager.javaClass.classLoader, arrayOf(Class.forName("android.app.IActivityManager")) ) { _, method, args -> if (method.name == "serviceDoneExecuting") { val token = args[0] as IBinder // 通过 token 找到对应的 Service 实例 val service = servicesByToken[token] service?.let { reachabilityWatcher.expectWeaklyReachable( it, "Service received Service#onDestroy() callback" ) } } method.invoke(iActivityManager, *args) } // 替换 ActivityThread 中的 mInstrumentation 或直接使用反射注入 proxy } }机制:由于 Android SDK 未暴露 Service 销毁的公开监听 API,ServiceWatcher通过反射 + 动态代理 HookIActivityManager来拦截serviceDoneExecuting()调用,从而感知 Service 销毁。
五、ObjectWatcher引用追踪核心
四个 Watcher 最终都调用reachabilityWatcher.expectWeaklyReachable(watchedObject, description),而默认的reachabilityWatcher就是AppWatcher.objectWatcher:
kotlin
val objectWatcher = ObjectWatcher( clock = { SystemClock.uptimeMillis() }, checkRetainedExecutor = { // 默认延迟 5s 后执行检查 mainHandler.postDelayed(it, retainedDelayMillis) }, isEnabled = { true } )ObjectWatcher内部使用ReferenceQueueRetainedObjectTracker:
kotlin
class ObjectWatcher : ReachabilityWatcher { private val watchedObjects = mutableMapOf<String, KeyedWeakReference>() private val queue = ReferenceQueue<Any>() private val onObjectRetainedListeners = mutableListOf<OnObjectRetainedListener>() override fun expectWeaklyReachable(watchedObject: Any, description: String) { val key = UUID.randomUUID().toString() // 1. 创建带 key 的弱引用,绑定到 ReferenceQueue val weakRef = KeyedWeakReference(watchedObject, key, description, queue) watchedObjects[key] = weakRef // 2. 延迟 5s 后检查 checkRetainedExecutor.execute { checkRetainedObjects(key) } } private fun checkRetainedObjects(key: String) { removeWeaklyReachableObjects() // 清除已入队的引用 val retainedRef = watchedObjects[key] if (retainedRef != null) { // 3. 手动触发 GC gcTrigger.runGc() removeWeaklyReachableObjects() if (watchedObjects.containsKey(key)) { // 4. GC 后仍未回收 → 通知 LeakCanary onObjectRetainedListeners.forEach { it.onObjectRetained() } } } } }检测逻辑:
目标对象销毁时,创建
KeyedWeakReference(带唯一 key)延迟 5s 后检查
ReferenceQueue若引用已入队 → 对象被回收,无泄漏
若未入队 → 手动触发
Runtime.getRuntime().gc()GC 后仍未入队 → 对象被保留(retained),通知所有
OnObjectRetainedListener
六、从 Retained 到 Heap Dump 的衔接
LeakCanaryDelegate.loadLeakCanary()会将InternalLeakCanary注册为OnObjectRetainedListener:
kotlin
internal object InternalLeakCanary : OnObjectRetainedListener { override fun onObjectRetained() { scheduleRetainedObjectCheck() } private fun scheduleRetainedObjectCheck() { backgroundHandler.postDelayed({ val retainedCount = AppWatcher.objectWatcher.retainedObjectCount when { retainedCount == 0 -> return // 前台且未达到阈值,仅显示通知 appVisible && retainedCount < LeakCanary.config.retainedVisibleThreshold -> showRetainedCountNotification(retainedCount) // 后台或达到阈值,执行 heap dump else -> dumpHeap() } }, 2000) } }触发条件:
应用进入后台 → 立即 dump
前台运行 → retained 对象数达到阈值(默认 5 个)才 dump
七、手动安装与自定义(关闭自动初始化)
如需关闭自动初始化并自定义 Watchers:
xml
<!-- res/values/leak_canary.xml --> <resources> <bool name="leak_canary_watcher_auto_install">false</bool> </resources>然后在Application.onCreate()中手动安装:
kotlin
class DebugApplication : Application() { override fun onCreate() { super.onCreate() // 示例 1:排除 ServiceWatcher(避免反射 Hook 带来的 ANR 风险) val watchersToInstall = AppWatcher.appDefaultWatchers(this) .filter { it !is ServiceWatcher } AppWatcher.manualInstall( application = this, watchersToInstall = watchersToInstall ) // 示例 2:自定义 ReachabilityWatcher 过滤特定类 val delegate = ReachabilityWatcher { watchedObject, description -> if (watchedObject !is BadSdkLeakingFragment) { AppWatcher.objectWatcher.expectWeaklyReachable(watchedObject, description) } } val customWatchers = AppWatcher.appDefaultWatchers(this, delegate) AppWatcher.manualInstall(application = this, watchersToInstall = customWatchers) } }八、完整启动时序图
应用进程启动 │ ▼ Application.attachBaseContext() │ ▼ ContentProvider.onCreate() ──► AppWatcherInstaller$MainProcess │ │ │ ▼ │ AppWatcher.manualInstall(application) │ │ │ ┌───────────────┼───────────────┐ │ ▼ ▼ ▼ │ LeakCanaryDelegate.loadLeakCanary() appDefaultWatchers(application) │ │ │ │ ▼ ▼ │ InternalLeakCanary.registerListener() [ActivityWatcher, FragmentAndViewModelWatcher, │ RootViewWatcher, ServiceWatcher] │ │ │ ▼ │ watchers.forEach { it.install() } │ │ │ ┌───────────────────────────────┼───────────────┐ │ ▼ ▼ ▼ ▼ │ registerActivityLifecycle registerFragmentLifecycle Curtains.onRootViewsChanged Hook IActivityManager │ │ │ │ │ ▼ ▼ ▼ ▼ ▼ Application.onCreate() ◄──────────────────────────────────────────────────────────────────── │ ▼ 应用正常运行 │ ▼ Activity/Fragment/View/Service 销毁 │ ▼ reachabilityWatcher.expectWeaklyReachable(obj, desc) │ ▼ ObjectWatcher ──► KeyedWeakReference + ReferenceQueue │ ▼ 延迟 5s ──► 检查 ReferenceQueue │ ├── 已清除 ──► 无泄漏 │ └── 未清除 ──► 触发 GC ──► 再次检查 │ ├── 已清除 ──► 无泄漏 │ └── 仍保留 ──► InternalLeakCanary.onObjectRetained() │ ▼ retainedCount >= threshold? │ ├── 否(前台)──► 通知栏提示 retained 数量 │ └── 是 ──► dumpHeap() ──► Shark 分析 ──► 泄漏报告总结
LeakCanary 2.7 的启动流程以appDefaultWatchers()为装配中心,通过ContentProvider实现零代码侵入自动初始化,通过ReachabilityWatcher接口实现 Watcher 与追踪引擎的解耦,通过InstallableWatcher.install()统一注册系统生命周期回调。四个默认 Watcher 覆盖了 Android 四大组件/核心对象中的 Activity、Fragment、ViewModel、View 和 Service,构成了完整的内存泄漏自动检测体系。
