公司动态

android LeakCanary 2.7 启动流程 详解

📅 2026/8/16 2:33:03
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 的模块化设计哲学kotlinfun appDefaultWatchers( application: Application, reachabilityWatcher: ReachabilityWatcher objectWatcher ): ListInstallableWatcher { 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中注册了自动初始化入口xmlprovider android:nameleakcanary.internal.AppWatcherInstaller$MainProcess android:authorities${applicationId}.leakcanary-installer android:enabledbool/leak_canary_watcher_auto_install android:exportedfalse /对应的AppWatcherInstaller源码kotlininternal 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内部执行流程kotlinJvmOverloads fun manualInstall( application: Application, retainedDelayMillis: Long TimeUnit.SECONDS.toMillis(5), watchersToInstall: ListInstallableWatcher 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.ActivityWatcherkotlininternal 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.FragmentAndViewModelWatcherkotlininternal 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.RootViewWatcher2.7 改进版kotlininternal 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.ServiceWatcherkotlininternal 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 销毁的公开监听 APIServiceWatcher通过反射 动态代理 HookIActivityManager来拦截serviceDoneExecuting()调用从而感知 Service 销毁。五、ObjectWatcher引用追踪核心四个 Watcher 最终都调用reachabilityWatcher.expectWeaklyReachable(watchedObject, description)而默认的reachabilityWatcher就是AppWatcher.objectWatcherkotlinval objectWatcher ObjectWatcher( clock { SystemClock.uptimeMillis() }, checkRetainedExecutor { // 默认延迟 5s 后执行检查 mainHandler.postDelayed(it, retainedDelayMillis) }, isEnabled { true } )ObjectWatcher内部使用ReferenceQueueRetainedObjectTrackerkotlinclass ObjectWatcher : ReachabilityWatcher { private val watchedObjects mutableMapOfString, KeyedWeakReference() private val queue ReferenceQueueAny() private val onObjectRetainedListeners mutableListOfOnObjectRetainedListener() 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注册为OnObjectRetainedListenerkotlininternal 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七、手动安装与自定义关闭自动初始化如需关闭自动初始化并自定义 Watchersxml!-- res/values/leak_canary.xml -- resources bool nameleak_canary_watcher_auto_installfalse/bool /resources然后在Application.onCreate()中手动安装kotlinclass 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构成了完整的内存泄漏自动检测体系。