美文网首页Android#Retrofit
LeakCanary 源码解析

LeakCanary 源码解析

作者: VanceKing | 来源:发表于2022-02-24 14:06 被阅读0次

    源码基于 com.squareup.leakcanary:leakcanary-android:2.7

    LeakCanary 初始化

    LeakCanary 通过 ContentProvider 完成自动初始化。

    <manifest
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.squareup.leakcanary.objectwatcher">
      <application>
        <provider
            android:name="leakcanary.internal.AppWatcherInstaller$MainProcess"
            android:authorities="${applicationId}.leakcanary-installer"
            android:enabled="@bool/leak_canary_watcher_auto_install"
            android:exported="false"/>
      </application>
    </manifest>
    
    internal sealed class AppWatcherInstaller : ContentProvider() {
        internal class MainProcess : AppWatcherInstaller()
        internal class LeakCanaryProcess : AppWatcherInstaller()
    
        override fun onCreate(): Boolean {
            val application = context!!.applicationContext as Application
            AppWatcher.manualInstall(application)
            return true
        }
    }
    
    object AppWatcher {
        fun manualInstall(
            application: Application,
            retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
            watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)) {
                checkMainThread()
                LeakCanaryDelegate.loadLeakCanary(application)
                watchersToInstall.forEach {
                    it.install()
                }
        }
    
        fun appDefaultWatchers(...): List<InstallableWatcher> {
            return listOf(
                ActivityWatcher(application, reachabilityWatcher),
                FragmentAndViewModelWatcher(application, reachabilityWatcher),
                RootViewWatcher(reachabilityWatcher),
                ServiceWatcher(reachabilityWatcher)
            )
        }
    }
    
    internal object LeakCanaryDelegate {
        // 因为 InternalLeakCanary 类是上层模块的,这里没有办法直接引用
        val loadLeakCanary by lazy {
            val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
            leakCanaryListener.getDeclaredField("INSTANCE")
                .get(null) as (Application) -> Unit
        }
    }
    
    internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
        override fun invoke(application: Application) {
            // 内存泄漏时回调该类的方法
            AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
            val heapDumper = AndroidHeapDumper(application, createLeakDirectoryProvider(application))
            heapDumpTrigger = HeapDumpTrigger(
                application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger, heapDumper, configProvider)
            // 动态添加Shortcut
            addDynamicShortcut(application)
        }
    }
    

    InternalLeakCanary 的部分声明为 object InternalLeakCanary : (Application) -> Unit,对应 kotlin 中 Functions.kt 文件的 Function1 接口,P1 为 Application,R 为 Unit 即 void:

    /** A function that takes 1 argument. */
    public interface Function1<in P1, out R> : Function<R> {
        /** Invokes the function with the specified argument. */
        public operator fun invoke(p1: P1): R
    }
    

    观察对象

    观察 Activity 对象

    class ActivityWatcher(
        private val application: Application,
        private val reachabilityWatcher: ReachabilityWatcher
    ) : InstallableWatcher {
    
        private val lifecycleCallbacks =
            object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
                override fun onActivityDestroyed(activity: Activity) {
                    reachabilityWatcher.expectWeaklyReachable(
                        activity, "${activity::class.java.name} received Activity#onDestroy() callback"
                    )
                }
            }
    
        override fun install() {
            application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
        }
    
        override fun uninstall() {
            application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
        }
    }
    

    通过 Application.ActivityLifecycleCallbacks#onActivityDestroyed() 监听 Activity 对象。

    观察 Fragment 对象

    class FragmentAndViewModelWatcher(
        private val application: Application,
        private val reachabilityWatcher: ReachabilityWatcher
    ) : InstallableWatcher {
        private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
            val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
    
            // AndroidOFragmentDestroyWatcher 观察 android.app.Fragment
            if (SDK_INT >= O) {
                fragmentDestroyWatchers.add(AndroidOFragmentDestroyWatcher(reachabilityWatcher))
            }
    
            // AndroidXFragmentDestroyWatcher 观察 androidx.fragment.app.Fragment
            getWatcherIfAvailable(
                ANDROIDX_FRAGMENT_CLASS_NAME,
                ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
                reachabilityWatcher
            )?.let {
                fragmentDestroyWatchers.add(it)
            }
    
            // AndroidSupportFragmentDestroyWatcher 观察 android.support.v4.app.Fragment
            getWatcherIfAvailable(
                ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
                ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
                reachabilityWatcher
            )?.let {
                fragmentDestroyWatchers.add(it)
            }
            fragmentDestroyWatchers
        }
    
        private val lifecycleCallbacks = object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
            override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle? ) {
                for (watcher in fragmentDestroyWatchers) {
                    watcher(activity)
                }
            }
        }
    
        override fun install() {
            application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
        }
    
        override fun uninstall() {
            application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
        }
    }
    

    通过 FragmentLifecycleCallbacks#onFragmentViewDestroyed() 和 onFragmentDestroyed() 监听 View 和 Fragment 对象。

    观察 RootView 对象

    class RootViewWatcher(
        private val reachabilityWatcher: ReachabilityWatcher
    ) : 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 -> rootView.resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
                        // Probably a DreamService
                        else -> true
                    }
                }
                // Android widgets keep detached popup window instances around.
                POPUP_WINDOW -> false
                TOOLTIP, TOAST, UNKNOWN -> true
            }
            if (trackDetached) {
                rootView.addOnAttachStateChangeListener(object : OnAttachStateChangeListener {
                    val watchDetachedView = Runnable {
                        reachabilityWatcher.expectWeaklyReachable(
                            rootView, "${rootView::class.java.name} received View#onDetachedFromWindow() callback"
                        )
                    }
    
                    override fun onViewAttachedToWindow(v: View) {
                        mainHandler.removeCallbacks(watchDetachedView)
                    }
    
                    override fun onViewDetachedFromWindow(v: View) {
                        mainHandler.post(watchDetachedView)
                    }
                })
            }
        }
    
        override fun install() {
            Curtains.onRootViewsChangedListeners += listener
        }
    
        override fun uninstall() {
            Curtains.onRootViewsChangedListeners -= listener
        }
    }
    

    通过 View.OnAttachStateChangeListener#onViewDetachedFromWindow() 监听 View 对象。

    观察 Service 对象

    通过 hook ActivityThread 的 H 类和 AMS,当 AMS 调用 serviceDoneExecuting 方法可做内存泄漏的检查工作。

    class ServiceWatcher(private val reachabilityWatcher: ReachabilityWatcher) : InstallableWatcher {
        override fun install() {
            // hook ActivityThread 中 H 类的 Callback
            swapActivityThreadHandlerCallback { mCallback ->
                Handler.Callback { msg ->
                    if (msg.what == STOP_SERVICE) {
                        val key = msg.obj as IBinder
                        activityThreadServices[key]?.let {
                            onServicePreDestroy(key, it)
                        }
                    }
                    mCallback?.handleMessage(msg) ?: false
                }
            }
            // hook AMS
            swapActivityManager { activityManagerInterface, activityManagerInstance ->
                Proxy.newProxyInstance(
                    activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
                ) { _, method, args ->
                    if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
                        val token = args!![0] as IBinder
                        if (servicesToBeDestroyed.containsKey(token)) {
                            onServiceDestroyed(token)
                        }
                    }
                }
            }
        }
    
        private fun onServiceDestroyed(token: IBinder) {
            servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
                serviceWeakReference.get()?.let { service ->
                    reachabilityWatcher.expectWeaklyReachable(
                        service, "${service::class.java.name} received Service#onDestroy() callback"
                    )
                }
            }
        }
    }
    

    通过动态代理,在调用 serviceDoneExecuting 方法时判断 Service 对象是否泄漏。

    检测泄漏对象

    class ObjectWatcher {
        private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
        private val queue = ReferenceQueue<Any>()
    
        @Synchronized override fun expectWeaklyReachable(watchedObject: Any, description: String) {
            removeWeaklyReachableObjects()
            val reference = KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
            watchedObjects[key] = reference
            // 主线程5秒之后执行moveToRetained(key)方法
            checkRetainedExecutor.execute {
                moveToRetained(key)
            }
        }
    
        @Synchronized private fun moveToRetained(key: String) {
            removeWeaklyReachableObjects()
            val retainedRef = watchedObjects[key]
            if (retainedRef != null) {
                retainedRef.retainedUptimeMillis = clock.uptimeMillis()
                // InternalLeakCanary 实现了 OnObjectRetainedListener
                onObjectRetainedListeners.forEach { it.onObjectRetained() }
            }
        }
    
        private fun removeWeaklyReachableObjects() {
            // WeakReferences are enqueued as soon as the object to which they point to becomes weakly
            // reachable. This is before finalization or garbage collection has actually happened.
            var ref: KeyedWeakReference?
            do {
                ref = queue.poll() as KeyedWeakReference?
                if (ref != null) {
                    watchedObjects.remove(ref.key)
                }
            } while (ref != null)
        }
    }
    
    1. 先移除队列中没有泄漏的对象;
    2. 把观察对象包装成 KeyedWeakReference 保存到引用队列中;
    3. 5s 后弱引用依然存在,可能存在内存泄漏,检测该对象。
    internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
        override fun onObjectRetained() = scheduleRetainedObjectCheck()
    
        fun scheduleRetainedObjectCheck() {
            if (this::heapDumpTrigger.isInitialized) {
                heapDumpTrigger.scheduleRetainedObjectCheck()
            }
        }
    }
    
    internal class HeapDumpTrigger(...) {
        fun scheduleRetainedObjectCheck(delayMillis: Long = 0L) {
            backgroundHandler.postDelayed({
                checkScheduledAt = 0
                checkRetainedObjects()
            }, delayMillis)
        }
    
        private fun checkRetainedObjects() {
            if (iCanHasHeap is Nope) {
                // 判断是否可以 dump 或通知
                return
            }
    
            var retainedReferenceCount = objectWatcher.retainedObjectCount
            if (retainedReferenceCount > 0) {
                gcTrigger.runGc()
                retainedReferenceCount = objectWatcher.retainedObjectCount
            }
    
            // 泄漏对象不超过 5 个,返回
            if (checkRetainedCount(retainedReferenceCount, config.retainedVisibleThreshold)) return
    
            // dump 间隔小于 60s,显示通知,重新调度
            if (elapsedSinceLastDumpMillis < WAIT_BETWEEN_HEAP_DUMPS_MILLIS) {
                showRetainedCountNotification()
                scheduleRetainedObjectCheck()
                return
            }
            dismissRetainedCountNotification()
            dumpHeap(...)
        }
    
        private fun dumpHeap(retainedReferenceCount: Int, retry: Boolean, reason: String) {
            saveResourceIdNamesToMemory()
            when (val heapDumpResult = heapDumper.dumpHeap()) {
                is NoHeapDump -> {
                    showRetainedCountNotification(...)
                }
                is HeapDump -> {
                    HeapAnalyzerService.runAnalysis(...)
                }
            }
        }
    }
    
    1. GC 后判断引用的对象数量;
    2. 泄漏对象 >= 5 时才显示通知,启动 HeapAnalyzerService 服务,dump 内存。

    dump 对象和分析 Hprof

    internal class HeapAnalyzerService : ForegroundService(...), OnAnalysisProgressListener {
        override fun onHandleIntentInForeground(intent: Intent?) {
            val heapAnalysis = if (heapDumpFile.exists()) {
                analyzeHeap(heapDumpFile, config)
            } else {
                missingFileFailure(heapDumpFile)
            }
            onAnalysisProgress(REPORTING_HEAP_ANALYSIS)
            config.onHeapAnalyzedListener.onHeapAnalyzed(fullHeapAnalysis)
        }
    
        private fun analyzeHeap(heapDumpFile: File, config: Config): HeapAnalysis {
            val heapAnalyzer = HeapAnalyzer(this)
            return heapAnalyzer.analyze()
        }
    }
    
    class HeapAnalyzer constructor(private val listener: OnAnalysisProgressListener) {
        fun analyze(...){
            listener.onAnalysisProgress(PARSING_HEAP_DUMP)
            val sourceProvider = ConstantMemoryMetricsDualSourceProvider(FileSourceProvider(heapDumpFile))
            sourceProvider.openHeapGraph(proguardMapping).use {
                val helpers = FindLeakInput(graph, ...)
                val result = helpers.analyzeGraph(metadataExtractor, ...)
            }
        }
    }
    

    总结

    LeakCanary 检测流程
    1. 通过 ContentProvider 初始化 LeakCanary;
    2. 在 Activity、Fragment、RootView 和 Service 对象的“终结”生命周期中观察对象;
    3. 生成 uuid,把观察的对象包装成弱引用,添加到引用队列;
    4. 如果泄漏对象 > 0,触发 GC,GC 后泄漏对象 >= 5 时,显示通知,dump 内存;
    5. 通过 shark 库分析 hprof 文件,查找泄露对象引用路径,存储分析结果。

    参考

    [1] square/leakcanary
    [2] LeakCanary Doc

    相关文章

      网友评论

        本文标题:LeakCanary 源码解析

        本文链接:https://www.haomeiwen.com/subject/spmzlrtx.html