流程 詳解)
LeakCanary 2.7 啟動(dòng)監(jiān)聽(tīng)流程基于appDefaultWatchers源碼以你給出的appDefaultWatchers()源碼為切入點(diǎn)LeakCanary 2.7 的啟動(dòng)流程可以拆解為自動(dòng)初始化 → 裝配 Watchers → 生命周期 Hook → 引用追蹤 → Heap Dump五個(gè)階段。下面按源碼層級(jí)逐步展開(kāi)。一、架構(gòu)設(shè)計(jì)從appDefaultWatchers看 2.7 的接口化改造你貼出的源碼是 LeakCanary 2.6 引入的核心 API它體現(xiàn)了 2.x 的模塊化設(shè)計(jì)哲學(xué)kotlinfun appDefaultWatchers( application: Application, reachabilityWatcher: ReachabilityWatcher objectWatcher ): ListInstallableWatcher { return listOf( ActivityWatcher(application, reachabilityWatcher), FragmentAndViewModelWatcher(application, reachabilityWatcher), RootViewWatcher(reachabilityWatcher), ServiceWatcher(reachabilityWatcher) ) }關(guān)鍵設(shè)計(jì)點(diǎn)設(shè)計(jì)說(shuō)明ReachabilityWatcher接口2.6 引入的 SAM 接口由ObjectWatcher實(shí)現(xiàn)。四個(gè) Watcher 不直接依賴(lài)ObjectWatcher而是依賴(lài)接口解耦了監(jiān)聽(tīng)觸發(fā)與引用追蹤InstallableWatcher接口每個(gè) Watcher 實(shí)現(xiàn)install()方法負(fù)責(zé)注冊(cè)系統(tǒng)回調(diào)或反射 Hook。manualInstall()只需遍歷調(diào)用it.install()即可統(tǒng)一注冊(cè)共享objectWatcher四個(gè) Watcher 共享同一個(gè)AppWatcher.objectWatcher實(shí)例確保所有被追蹤對(duì)象都在同一個(gè)watchedObjectsMap 中管理二、自動(dòng)初始化鏈路ContentProvider 觸發(fā)leakcanary-android:2.7依賴(lài)的AndroidManifest.xml中注冊(cè)了自動(dòng)初始化入口xmlprovider android:nameleakcanary.internal.AppWatcherInstaller$MainProcess android:authorities${applicationId}.leakcanary-installer android:enabledbool/leak_canary_watcher_auto_install android:exportedfalse /對(duì)應(yīng)的AppWatcherInstaller源碼kotlininternal sealed class AppWatcherInstaller : ContentProvider() { internal class MainProcess : AppWatcherInstaller() override fun onCreate(): Boolean { val application context!!.applicationContext as Application AppWatcher.manualInstall(application) // 默認(rèn)調(diào)用watchersToInstall appDefaultWatchers(application) return true } }執(zhí)行時(shí)序Application.attachBaseContext()→ContentProvider.onCreate()→Application.onCreate()。LeakCanary 在Application.onCreate()之前就已經(jīng)完成所有 Watcher 的注冊(cè)。三、manualInstall內(nèi)部執(zhí)行流程kotlinJvmOverloads fun manualInstall( application: Application, retainedDelayMillis: Long TimeUnit.SECONDS.toMillis(5), watchersToInstall: ListInstallableWatcher appDefaultWatchers(application) ) { checkMainThread() // ① 必須在主線程 if (isInstalled) { // ② 防重入保護(hù) throw IllegalStateException(AppWatcher already installed) } // ③ 加載 LeakCanary 分析引擎如果 classpath 中存在 LeakCanaryDelegate.loadLeakCanary(application) // ④ 遍歷安裝所有 Watcher watchersToInstall.forEach { it.install() } }關(guān)鍵步驟解析LeakCanaryDelegate.loadLeakCanary(application)通過(guò)反射查找InternalLeakCanary類(lèi)并實(shí)例化將AppWatcher.objectWatcher注冊(cè)為OnObjectRetainedListener。這樣當(dāng)ObjectWatcher檢測(cè)到 retained 對(duì)象時(shí)能觸發(fā)后續(xù)的 heap dump。watchersToInstall.forEach { it.install() }調(diào)用你列出的四個(gè) Watcher 的install()方法分別向系統(tǒng)注冊(cè)生命周期監(jiān)聽(tīng)。四、四大 Watcher 的注冊(cè)與實(shí)現(xiàn)細(xì)節(jié)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 ) } // 其他生命周期方法為空實(shí)現(xiàn) } override fun install() { application.registerActivityLifecycleCallbacks(lifecycleCallbacks) } }機(jī)制通過(guò)Application.registerActivityLifecycleCallbacks()監(jiān)聽(tīng)所有 Activity 的onDestroy()銷(xiāo)毀時(shí)立即將 Activity 實(shí)例交給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?) { // 注冊(cè) Fragment 生命周期回調(diào) (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) // 同時(shí)追蹤 Fragment 的 View fragment.view?.let { view - reachabilityWatcher.expectWeaklyReachable(view, Fragment view destroyed) } } override fun onFragmentViewDestroyed(fm: FragmentManager, fragment: Fragment) { // ViewModel 監(jiān)聽(tīng)通過(guò) ViewModelStore 實(shí)現(xiàn) watchViewModel(fragment) } } }機(jī)制利用FragmentManager.FragmentLifecycleCallbacks監(jiān)聽(tīng)Fragment.onDestroy()Fragment 的 View 和 ViewModel 分別獨(dú)立追蹤ViewModel 通過(guò)ViewModelStore的onCleared()回調(diào)觸發(fā)追蹤3.RootViewWatcher2.7 改進(jìn)版kotlininternal class RootViewWatcher( private val reachabilityWatcher: ReachabilityWatcher ) : InstallableWatcher { override fun install() { // 2.7 使用 Curtains 庫(kù)替代直接注冊(cè) OnAttachStateChangeListener Curtains.onRootViewsChangedListeners OnRootViewRemovedListener { rootView - if (rootView.windowType WindowType.PHONE_WINDOW) { // 2.7 默認(rèn)忽略 PopupWindow 和 Dialog 的 root view // 可通過(guò)資源 bool leak_canary_watcher_watch_dismissed_dialogs 開(kāi)啟 if (rootView.watchDismissedDialogs || rootView !is DialogRootView) { reachabilityWatcher.expectWeaklyReachable( rootView, View detached from window ) } } } } }2.7 關(guān)鍵改進(jìn)引入Curtains庫(kù)來(lái)統(tǒng)一監(jiān)聽(tīng) Window/RootView 的添加和移除解決了 2.6 中誤報(bào) PopupWindow/Dialog 的問(wèn)題。默認(rèn)行為? 繼續(xù)檢測(cè) Toast 的 root view 泄漏? 忽略PopupWindow創(chuàng)建的 root view? 忽略Dialog創(chuàng)建的 root view可通過(guò)leak_canary_watcher_watch_dismissed_dialogs資源布爾值開(kāi)啟4.ServiceWatcherkotlininternal class ServiceWatcher(private val reachabilityWatcher: ReachabilityWatcher) : InstallableWatcher { override fun install() { // Android SDK 沒(méi)有 Service 生命周期公開(kāi) API通過(guò)反射 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 // 通過(guò) token 找到對(duì)應(yīng)的 Service 實(shí)例 val service servicesByToken[token] service?.let { reachabilityWatcher.expectWeaklyReachable( it, Service received Service#onDestroy() callback ) } } method.invoke(iActivityManager, *args) } // 替換 ActivityThread 中的 mInstrumentation 或直接使用反射注入 proxy } }機(jī)制由于 Android SDK 未暴露 Service 銷(xiāo)毀的公開(kāi)監(jiān)聽(tīng) APIServiceWatcher通過(guò)反射 動(dòng)態(tài)代理 HookIActivityManager來(lái)攔截serviceDoneExecuting()調(diào)用從而感知 Service 銷(xiāo)毀。五、ObjectWatcher引用追蹤核心四個(gè) Watcher 最終都調(diào)用reachabilityWatcher.expectWeaklyReachable(watchedObject, description)而默認(rèn)的reachabilityWatcher就是AppWatcher.objectWatcherkotlinval objectWatcher ObjectWatcher( clock { SystemClock.uptimeMillis() }, checkRetainedExecutor { // 默認(rèn)延遲 5s 后執(zhí)行檢查 mainHandler.postDelayed(it, retainedDelayMillis) }, isEnabled { true } )ObjectWatcher內(nèi)部使用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. 創(chuàng)建帶 key 的弱引用綁定到 ReferenceQueue val weakRef KeyedWeakReference(watchedObject, key, description, queue) watchedObjects[key] weakRef // 2. 延遲 5s 后檢查 checkRetainedExecutor.execute { checkRetainedObjects(key) } } private fun checkRetainedObjects(key: String) { removeWeaklyReachableObjects() // 清除已入隊(duì)的引用 val retainedRef watchedObjects[key] if (retainedRef ! null) { // 3. 手動(dòng)觸發(fā) GC gcTrigger.runGc() removeWeaklyReachableObjects() if (watchedObjects.containsKey(key)) { // 4. GC 后仍未回收 → 通知 LeakCanary onObjectRetainedListeners.forEach { it.onObjectRetained() } } } } }檢測(cè)邏輯目標(biāo)對(duì)象銷(xiāo)毀時(shí)創(chuàng)建KeyedWeakReference帶唯一 key延遲 5s 后檢查ReferenceQueue若引用已入隊(duì) → 對(duì)象被回收無(wú)泄漏若未入隊(duì) → 手動(dòng)觸發(fā)Runtime.getRuntime().gc()GC 后仍未入隊(duì) → 對(duì)象被保留retained通知所有OnObjectRetainedListener六、從 Retained 到 Heap Dump 的銜接LeakCanaryDelegate.loadLeakCanary()會(huì)將InternalLeakCanary注冊(cè)為OnObjectRetainedListenerkotlininternal object InternalLeakCanary : OnObjectRetainedListener { override fun onObjectRetained() { scheduleRetainedObjectCheck() } private fun scheduleRetainedObjectCheck() { backgroundHandler.postDelayed({ val retainedCount AppWatcher.objectWatcher.retainedObjectCount when { retainedCount 0 - return // 前臺(tái)且未達(dá)到閾值僅顯示通知 appVisible retainedCount LeakCanary.config.retainedVisibleThreshold - showRetainedCountNotification(retainedCount) // 后臺(tái)或達(dá)到閾值執(zhí)行 heap dump else - dumpHeap() } }, 2000) } }觸發(fā)條件應(yīng)用進(jìn)入后臺(tái) → 立即 dump前臺(tái)運(yùn)行 → retained 對(duì)象數(shù)達(dá)到閾值默認(rèn) 5 個(gè)才 dump七、手動(dòng)安裝與自定義關(guān)閉自動(dòng)初始化如需關(guān)閉自動(dòng)初始化并自定義 Watchersxml!-- res/values/leak_canary.xml -- resources bool nameleak_canary_watcher_auto_installfalse/bool /resources然后在Application.onCreate()中手動(dòng)安裝kotlinclass DebugApplication : Application() { override fun onCreate() { super.onCreate() // 示例 1排除 ServiceWatcher避免反射 Hook 帶來(lái)的 ANR 風(fēng)險(xiǎn) val watchersToInstall AppWatcher.appDefaultWatchers(this) .filter { it !is ServiceWatcher } AppWatcher.manualInstall( application this, watchersToInstall watchersToInstall ) // 示例 2自定義 ReachabilityWatcher 過(guò)濾特定類(lèi) 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) } }八、完整啟動(dòng)時(shí)序圖應(yīng)用進(jìn)程啟動(dòng) │ ▼ 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() ?──────────────────────────────────────────────────────────────────── │ ▼ 應(yīng)用正常運(yùn)行 │ ▼ Activity/Fragment/View/Service 銷(xiāo)毀 │ ▼ reachabilityWatcher.expectWeaklyReachable(obj, desc) │ ▼ ObjectWatcher ──? KeyedWeakReference ReferenceQueue │ ▼ 延遲 5s ──? 檢查 ReferenceQueue │ ├── 已清除 ──? 無(wú)泄漏 │ └── 未清除 ──? 觸發(fā) GC ──? 再次檢查 │ ├── 已清除 ──? 無(wú)泄漏 │ └── 仍保留 ──? InternalLeakCanary.onObjectRetained() │ ▼ retainedCount threshold? │ ├── 否前臺(tái)──? 通知欄提示 retained 數(shù)量 │ └── 是 ──? dumpHeap() ──? Shark 分析 ──? 泄漏報(bào)告總結(jié)LeakCanary 2.7 的啟動(dòng)流程以appDefaultWatchers()為裝配中心通過(guò)ContentProvider實(shí)現(xiàn)零代碼侵入自動(dòng)初始化通過(guò)ReachabilityWatcher接口實(shí)現(xiàn) Watcher 與追蹤引擎的解耦通過(guò)InstallableWatcher.install()統(tǒng)一注冊(cè)系統(tǒng)生命周期回調(diào)。四個(gè)默認(rèn) Watcher 覆蓋了 Android 四大組件/核心對(duì)象中的 Activity、Fragment、ViewModel、View 和 Service構(gòu)成了完整的內(nèi)存泄漏自動(dòng)檢測(cè)體系。