美文网首页Android细碎技术知识点Hadoop安卓进阶
LeakCanary最新2.8.1版本源码 原理分析 [2022

LeakCanary最新2.8.1版本源码 原理分析 [2022

作者: jalen2024 | 来源:发表于2022-01-22 17:20 被阅读0次

    首先从LeakCanary的使用开始讲,接着会到底层分析源码逻辑

    kotlin新版本如何使用

    dependencies {
      // debugImplementation because LeakCanary should only run in debug builds.
      debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
    }
    

    只需要这样一步就搞定了.

    默认监测哪些泄漏

    官方网站的说明,无侵入式依赖,会自动给注入如下几个模块的内存泄漏监听

    LeakCanary automatically detects leaks of the following objects:

    destroyed Activity instances
    destroyed Fragment instances
    destroyed fragment View instances
    cleared ViewModel instances

    整体工作流程

    它会经过下面4个步骤来完成所有的工作.

    • Detecting retained objects. 监测保留未被回收的对象
    • Dumping the heap. 转储堆区
    • Analyzing the heap. 分析堆区
    • Categorizing leaks. 堆泄漏进行分来

    监测未被回收的对象

    在前台可见的时候,是监听到有5个未回收的对象就会开始dump

    在后台不可见的时候,是监听到有1个未被回收的对象就会开始dump.

    2秒钟监测一次,dump的周期是5秒钟一次.

    转储堆

    当达到上面的阈值情况下,就会触发dump,
    生成.hprof文件

    分析堆区

    现在是通过Shark来分析

    泄漏分类

    ################################

    步入正题,死磕源码.

    编译后的文件里会有自动注入一些provider和activity.

    如图所示


    1.png 2.png 3.png

    1: ProcessLifecycleOwnerInitializer

    androidx.lifecycle.ProcessLifecycleOwnerInitializer

    这是安卓系统自带的一个ContentProvider

    在onCreate方法里主要做了2个操作

    LifecycleDispatcher.init(getContext());
    ProcessLifecycleOwner.init(getContext());
    

    1.1: LifecycleDispatcher

    //底层会在application中把这个callback纳入application的维护范畴内
    ((Application) context.getApplicationContext())
                    .registerActivityLifecycleCallbacks(new DispatcherActivityCallback());
    

    在注意看DispatcherActivityCallback中其实就做了一个事情

        @VisibleForTesting
        static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {
    
            @Override
            public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
               //核心就是这句了.
                ReportFragment.injectIfNeededIn(activity);
            }
    ..........省略.......................
        }
    

    上面的回调Callback 是Application中的一个接口<ActivityLifecycleCallbacks>,同时Application中维护了一个ArrayList<ActivityLifecycleCallbacks>

     @UnsupportedAppUsage
        private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
                new ArrayList<ActivityLifecycleCallbacks>();
    

    1.2: ProcessLifecycleOwner

      static void init(Context context) {
            sInstance.attach(context);
        }
    
    void attach(Context context) {
            mHandler = new Handler();
            mRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
            Application app = (Application) context.getApplicationContext();
            //核心还是下面这行代码了 注册activity的生命周期回调
            app.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
                @Override
                public void onActivityPreCreated(@NonNull Activity activity,
                        @Nullable Bundle savedInstanceState) {
                    activity.registerActivityLifecycleCallbacks(new EmptyActivityLifecycleCallbacks() {
                    .......省略.......
                    onActivityPostStarted
                    .......省略.......
                    onActivityPostResumed
                   .......省略.......
                    });
                }
    
                @Override
                public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
                    if (Build.VERSION.SDK_INT < 29) {
                        ReportFragment.get(activity).setProcessListener(mInitializationListener);
                    }
                }
              .......省略.......
            });
        }
    

    **总结: 上面的2个生命周期注册回调 ,最终都是在Application类中处理的.

    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
            synchronized (mActivityLifecycleCallbacks) {
                mActivityLifecycleCallbacks.add(callback);
            }
        }
    
        public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
            synchronized (mActivityLifecycleCallbacks) {
                mActivityLifecycleCallbacks.remove(callback);
            }
        }
    

    2: LeakCanaryFileProvider

    leakcanary.internal.LeakCanaryFileProvider

    这个类我也没看懂具体看嘛的, 大概意思就是操作file类时使用到.

    3: MainProcessAppWatcherInstaller

    leakcanary.internal.MainProcessAppWatcherInstaller

    这个类也是集成了ContentProvider, 替代了以前老版本LeackCanary手动install, 在这个类的onCreate方法中会自动执行如下操作[神来之笔]

     override fun onCreate(): Boolean {
        val application = context!!.applicationContext as Application
        AppWatcher.manualInstall(application)
        return true
      }
    

    3.1: 核心代码

     @JvmOverloads
      fun manualInstall(
        application: Application,
        retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
        watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
      ) {
      //校验当前是否在主线程  Looper.getMainLooper().thread === Thread.currentThread()
        checkMainThread()
        if (isInstalled) {
          throw IllegalStateException(
            "AppWatcher already installed, see exception cause for prior install call", installCause
          )
        }
        check(retainedDelayMillis >= 0) {
          "retainedDelayMillis $retainedDelayMillis must be at least 0 ms"
        }
        installCause = RuntimeException("manualInstall() first called here")
        this.retainedDelayMillis = retainedDelayMillis
        if (application.isDebuggableBuild) {
        //debug模式 打开日志开关
          LogcatSharkLog.install()
        }
        // Requires AppWatcher.objectWatcher to be set
        LeakCanaryDelegate.loadLeakCanary(application)
    
        watchersToInstall.forEach {
          it.install()
        }
      }
    

    3.2: 反射加载InternalLeakCanary

      @Suppress("UNCHECKED_CAST")
      val loadLeakCanary by lazy {
        try {
          val leakCanaryListener = Class.forName("leakcanary.internal.InternalLeakCanary")
          leakCanaryListener.getDeclaredField("INSTANCE")
            .get(null) as (Application) -> Unit
        } catch (ignored: Throwable) {
          NoLeakCanary
        }
      }
    

    上面传参As Application会执行到invoke方法

    internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
    ..................省略................
    
    override fun invoke(application: Application) {
        _application = application
     //校验是否开启了只在debug模式使用. 设计原理只给debug时候使用
        checkRunningInDebuggableBuild()
        //创建AppWatcher对象 同时设置监听
        AppWatcher.objectWatcher.addOnObjectRetainedListener(this)
        //GC回收工具
        val gcTrigger = GcTrigger.Default
    
        val configProvider = { LeakCanary.config }
        //创建异步线程
        val handlerThread = HandlerThread(LEAK_CANARY_THREAD_NAME)
        handlerThread.start()
        //异步线程用于后台服务
        val backgroundHandler = Handler(handlerThread.looper)
    
        heapDumpTrigger = HeapDumpTrigger(
          application, backgroundHandler, AppWatcher.objectWatcher, gcTrigger,
          configProvider
        )
        //监听应用是否可见的状态 可见和不可见 retained的阈值不一样  5 ---1
        application.registerVisibilityListener { applicationVisible ->
          this.applicationVisible = applicationVisible
          //通知更新 如果可能话这里会触发转储堆
          heapDumpTrigger.onApplicationVisibilityChanged(applicationVisible)
        }
        //监听onResume onPause
        registerResumedActivityListener(application)
        //创建桌面快捷图标 点击直接进入LeakActivity
        addDynamicShortcut(application)
        
     
        mainHandler.post {
         backgroundHandler.post {
            SharkLog.d {
              //校验是否可以dump  如果可以dump的话 则发送notification的广播
              when (val iCanHasHeap = HeapDumpControl.iCanHasHeap()) {
                is Yup -> application.getString(R.string.leak_canary_heap_dump_enabled_text)
                is Nope -> application.getString(
                  R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
                )
              }
            }
          }
        }
    
    

    综上所述:通过Android里ContentProvider的特有机制,自动触发install操作,在install操作中再通过类的反射去invoke执行.

    • 校验是否只开启debug模式使用
    • 创建Watcher对象并监听
    • 创建GC回收器
    • 创建后台异步线程
    • 监听应用可见与否,并调用不同的阈值策略进行dump heap
    • 创建桌面快捷图标

    3.3: 不同的监听器自动注入

    在AppWatcher的注册里面最后3行 有很关键的动作,如下

    watchersToInstall.forEach {
          it.install()
        }
    
    watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
    

    四大金刚正式登场

      fun appDefaultWatchers(
        application: Application,
        reachabilityWatcher: ReachabilityWatcher = objectWatcher
      ): List<InstallableWatcher> {
        return listOf(
          ActivityWatcher(application, reachabilityWatcher),
          FragmentAndViewModelWatcher(application, reachabilityWatcher),
          RootViewWatcher(reachabilityWatcher),
          ServiceWatcher(reachabilityWatcher)
        )
      }
    

    很多朋友反馈LeakCanary老版本功能有限,只监听Activity和Fragment, 不能监听Service, 这次给安排上了.

    3.3.1: ActivityWatcher

    继承InstallableWatcher接口 只有install和unInstall2个方法, 通过声明一个全局变量来做下面的操作

     private val lifecycleCallbacks =
        object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
          override fun onActivityDestroyed(activity: Activity) {
            //watchObject 和 description 这个描述会Log日志
            reachabilityWatcher.expectWeaklyReachable(
              activity, "${activity::class.java.name} received Activity#onDestroy() callback"
            )
          }
        }
    
      override fun install() {
        application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
      }
    
      override fun uninstall() {
        application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
      }
    

    3.3.2: FragmentAndViewModelWatcher

    这里面底层其实还是依赖于Activity, 同时还细分兼容为如下的
    Android8.0及以上的

    Android x系列的Fragment

    Android support系列的fragment

    //定义List<Activity>的集合 
      private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
        val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()
    
        //大于等于8.0版本的AndroidOFragmentDestroyWatcher
        if (SDK_INT >= O) {
          fragmentDestroyWatchers.add(
            AndroidOFragmentDestroyWatcher(reachabilityWatcher)
          )
        }
    
        //AndroidX 里的Fragment
        getWatcherIfAvailable(
          ANDROIDX_FRAGMENT_CLASS_NAME,
          ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
          reachabilityWatcher
        )?.let {
          fragmentDestroyWatchers.add(it)
        }
    
        //support系列里的Fragment
        getWatcherIfAvailable(
          ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
          ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
          reachabilityWatcher
        )?.let {
          fragmentDestroyWatchers.add(it)
        }
        fragmentDestroyWatchers
      }
    

    fragmentDestroyWatchers 的使用

    private val lifecycleCallbacks =
        object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
          override fun onActivityCreated(
            activity: Activity,
            savedInstanceState: Bundle?
          ) {
            for (watcher in fragmentDestroyWatchers) {
              watcher(activity)
            }
          }
        }
    
    3.3.2.1: AndroidOFragmentDestroyWatcher
    import android.app.Fragment
    import android.app.FragmentManager
    
     private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
    
        override fun onFragmentViewDestroyed(
          fm: FragmentManager,
          fragment: Fragment
        ) {
          val view = fragment.view
          if (view != null) {
            reachabilityWatcher.expectWeaklyReachable(
              view, "${fragment::class.java.name} received Fragment#onDestroyView() callback " +
              "(references to its views should be cleared to prevent leaks)"
            )
          }
        }
    
        override fun onFragmentDestroyed(
          fm: FragmentManager,
          fragment: Fragment
        ) {
          reachabilityWatcher.expectWeaklyReachable(
            fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
          )
        }
      }
    
    //底层执行 通过寄存的Activity获取到对应的FragmentManager 设置生命周期回调
      override fun invoke(activity: Activity) {
        val fragmentManager = activity.fragmentManager
        fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
      }
    
    3.3.2.2: AndroidXFragmentDestroyWatcher 和上面的有区别

    和AndroidOFragmentDestroyWatcher写法一样,唯一就是导入的fragment包不一样 ,以及多了2个重写的方法处理

    import androidx.fragment.app.Fragment
    import androidx.fragment.app.FragmentActivity
    import androidx.fragment.app.FragmentManager
    
    private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {
    
        //比androidOFragmentDestroyWatcher多了下面这些处理
        override fun onFragmentCreated(
          fm: FragmentManager,
          fragment: Fragment,
          savedInstanceState: Bundle?
        ) {
          ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
        }
    
        override fun onFragmentViewDestroyed......省略同AndroidOFragmentDestroyWatcher里..... }
        
         override fun onFragmentDestroyed......省略同AndroidOFragmentDestroyWatcher里..... }
    
    
      override fun invoke(activity: Activity) {
        if (activity is FragmentActivity) {
          val supportFragmentManager = activity.supportFragmentManager
          supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
          //比androidOFragmentDestroyWatcher多了下面这一行 
          ViewModelClearedWatcher.install(activity, reachabilityWatcher)
        }
      }
    

    通过Androidx 里的ViewModel

      companion object {
        fun install(
          storeOwner: ViewModelStoreOwner,
          reachabilityWatcher: ReachabilityWatcher
        ) {
          val provider = ViewModelProvider(storeOwner, object : Factory {
            @Suppress("UNCHECKED_CAST")
            override fun <T : ViewModel?> create(modelClass: Class<T>): T =
              ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
          })
          provider.get(ViewModelClearedWatcher::class.java)
        }
      }
    
    3.3.2.3: AndroidSupportFragmentDestroyWatcher

    和AndroidOFragmentDestroyWatcher一样,唯一就是引用的Fragment包不一样

    import android.support.v4.app.Fragment
    import android.support.v4.app.FragmentActivity
    import android.support.v4.app.FragmentManager
    

    综上所述,在fragmentWatcher处理的时候由区分兼容处理,最终通过Fragment依赖的Activity中fragmentManager进行生命周期管理.

    3.3.3: RootViewWatcher

    主要处理View相关的,前提是View不依附于Activity/popWindow, 以及项目中配置的是否支持弹窗

    private val listener = OnRootViewAddedListener { rootView ->
        val trackDetached = when(rootView.windowType) {
          PHONE_WINDOW -> {
            when (rootView.phoneWindow?.callback?.wrappedCallback) {
              // Activities are already tracked by ActivityWatcher
                //如果是依附于activity的就不处理
              is Activity -> false
              //如果是弹窗里的 则根据配置文件来觉得
              is Dialog -> {
                // Use app context resources to avoid NotFoundException
                // https://github.com/square/leakcanary/issues/2137
                val resources = rootView.context.applicationContext.resources
                resources.getBoolean(R.bool.leak_canary_watcher_watch_dismissed_dialogs)
              }
              // Probably a DreamService
              else -> true
            }
          }
          // Android widgets keep detached popup window instances around.
          //依赖于pop window的也不处理
          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)
            }
          })
        }
      }
    

    3.3.4: ServiceWatcher

    弱引用关联

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

    反射创建

     private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }
    
      private val activityThreadInstance by lazy {
        activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)!!
      }
    
      private val activityThreadServices by lazy {
        val mServicesField =
          activityThreadClass.getDeclaredField("mServices").apply { isAccessible = true }
    
        @Suppress("UNCHECKED_CAST")
        mServicesField[activityThreadInstance] as Map<IBinder, Service>
      }
    

    service这里面的核心源码暂时没看懂, 大概能知道是就是有反射调用IActivityManager

    install方法里的核心源码贴一下

    try {
          swapActivityThreadHandlerCallback { mCallback ->
            uninstallActivityThreadHandlerCallback = {
              swapActivityThreadHandlerCallback {
                mCallback
              }
            }
            Handler.Callback { msg ->
              // https://github.com/square/leakcanary/issues/2114
              // On some Motorola devices (Moto E5 and G6), the msg.obj returns an ActivityClientRecord
              // instead of an IBinder. This crashes on a ClassCastException. Adding a type check
              // here to prevent the crash.
              if (msg.obj !is IBinder) {
                return@Callback false
              }
    
              if (msg.what == STOP_SERVICE) {
                val key = msg.obj as IBinder
                activityThreadServices[key]?.let {
                  onServicePreDestroy(key, it)
                }
              }
              mCallback?.handleMessage(msg) ?: false
            }
          }
          swapActivityManager { activityManagerInterface, activityManagerInstance ->
            uninstallActivityManager = {
              swapActivityManager { _, _ ->
                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)
                }
              }
              try {
                if (args == null) {
                  method.invoke(activityManagerInstance)
                } else {
                  method.invoke(activityManagerInstance, *args)
                }
              } catch (invocationException: InvocationTargetException) {
                throw invocationException.targetException
              }
            }
          }
        } catch (ignored: Throwable) {
          SharkLog.d(ignored) { "Could not watch destroyed services" }
        }
    

    综上,我们知道 为什么新版本leakCanary只要依赖就行. 因为上面都是自动给处理了的.

    4: 接着分析转储堆区

    我们在AppWatcher类里面维护着一个ObjectWatcher类

    class ObjectWatcher constructor(
      private val clock: Clock,
      private val checkRetainedExecutor: Executor,
      /**
       * Calls to [watch] will be ignored when [isEnabled] returns false
       */
      private val isEnabled: () -> Boolean = { true }
    ) : ReachabilityWatcher {
    

    4.1: 在 AppWatcher 类里面如下

      @Volatile
      var retainedDelayMillis = RETAINED_DELAY_NOT_SET
      
      
     val objectWatcher = ObjectWatcher(
        clock = { SystemClock.uptimeMillis() },
        checkRetainedExecutor = {
          check(isInstalled) {
            "AppWatcher not installed"
          }
          //重要操作 发送延迟操作的任务  
          mainHandler.postDelayed(it, retainedDelayMillis)
        },//传
        isEnabled = { true }
      ),
        isEnabled = { true }
    

    上面所提到的handler就是主线程的handler

    internal val mainHandler by lazy { Handler(Looper.getMainLooper()) }
    

    在InternalLeakCanary的invoke执行方法里面,有监测的时候发送Notification的操作

    5: NotificationReceiver

    这个类主要负责接收广播事件 DUMP_HEAP的操作,

    5.1: 在上面的3.3步骤中是可以看到发送广播的处理

    backgroundHandler.post {
            SharkLog.d {
              //校验是否可以dump  如果可以dump的话 则发送notification的广播
              when (val iCanHasHeap = HeapDumpControl.iCanHasHeap()) {
                is Yup -> application.getString(R.string.leak_canary_heap_dump_enabled_text)
                is Nope -> application.getString(
                  R.string.leak_canary_heap_dump_disabled_text, iCanHasHeap.reason()
                )
              }
            }
          }
    

    5.2 在HenapDumpControl类中

    fun iCanHasHeap(): ICanHazHeap {
        ........省略代码.........
    
        synchronized(this) {
          if (::latest.isInitialized && dumpHeap is Yup && latest is Nope) {
            //dump的调度处理
            InternalLeakCanary.scheduleRetainedObjectCheck()
          }
          latest = dumpHeap
        }
    
        return dumpHeap
      }
    

    5.3: 在INternalLeakCanary中

      fun scheduleRetainedObjectCheck() {
        if (this::heapDumpTrigger.isInitialized) {
          heapDumpTrigger.scheduleRetainedObjectCheck()
        }
      }
    

    5.4 在HeapDumpTrigger中

    fun scheduleRetainedObjectCheck(
        delayMillis: Long = 0L
      ) {
        val checkCurrentlyScheduledAt = checkScheduledAt
        if (checkCurrentlyScheduledAt > 0) {
          return
        }
        checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
        backgroundHandler.postDelayed({
          checkScheduledAt = 0
          //检查是否需要dump的地方 根据需要的时候就发送广播出去
          checkRetainedObjects()
        }, delayMillis)
      }
    

    5.6 在广播中接收处理

     override fun onReceive(
        context: Context,
        intent: Intent
      ) {
        when (intent.action) {
          DUMP_HEAP.name -> {
          //具体的执行看下面5.7
            InternalLeakCanary.onDumpHeapReceived(forceDump = false)
          }
          CANCEL_NOTIFICATION.name -> {
            // Do nothing, the notification has auto cancel true.
          }
          else -> {
            SharkLog.d { "NotificationReceiver received unknown intent action for $intent" }
          }
        }
      }
    

    5.7: InternalLeakCanary类中的Dump接收处理

     fun onDumpHeapReceived(forceDump: Boolean) {
        if (this::heapDumpTrigger.isInitialized) {
          heapDumpTrigger.onDumpHeapReceived(forceDump)
        }
      }
    

    5.8 在HeapDumpTrigger中的处理

    fun onDumpHeapReceived(forceDump: Boolean) {
        backgroundHandler.post {
          //取消notify提示
          dismissNoRetainedOnTapNotification()
          //手动执行GC 底层调用 Runtime.getRuntime().gc()
          gcTrigger.runGc()
          val retainedReferenceCount = objectWatcher.retainedObjectCount
          if (!forceDump && retainedReferenceCount == 0) {
           ....省略代码.......
            return@post
          }
    
          SharkLog.d { "Dumping the heap because user requested it" }
          //重要操作
          dumpHeap(retainedReferenceCount, retry = false, "user request")
        }
      }
    

    5.9 dumpHeap的处理

     private fun dumpHeap(
        retainedReferenceCount: Int,
        retry: Boolean,
        reason: String
      ) {
        //创建存储dump 文件的 目录
        val directoryProvider =
          InternalLeakCanary.createLeakDirectoryProvider(InternalLeakCanary.application)
        //在dump文件夹创建新的dump文件    目录context.cacheDir
        val heapDumpFile = directoryProvider.newHeapDumpFile()
    
        val durationMillis: Long
        try {
          //发送事件  当前的事件唯一id
          InternalLeakCanary.sendEvent(DumpingHeap(currentEventUniqueId))
          if (heapDumpFile == null) {
            throw RuntimeException("Could not create heap dump file")
          }
          saveResourceIdNamesToMemory()
          val heapDumpUptimeMillis = SystemClock.uptimeMillis()
          //UUID为key 的一个弱引用因 
          KeyedWeakReference.heapDumpUptimeMillis = heapDumpUptimeMillis
          durationMillis = measureDurationMillis {
            configProvider().heapDumper.dumpHeap(heapDumpFile)
          }
          if (heapDumpFile.length() == 0L) {
            throw RuntimeException("Dumped heap file is 0 byte length")
          }
          lastDisplayedRetainedObjectCount = 0
          lastHeapDumpUptimeMillis = SystemClock.uptimeMillis()
          objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)
          currentEventUniqueId = UUID.randomUUID().toString()
          InternalLeakCanary.sendEvent(HeapDump(currentEventUniqueId, heapDumpFile, durationMillis, reason))
    

    5.10 LeakCanary类中的事件集合

     val eventListeners: List<EventListener> = listOf(
          LogcatEventListener,
          ToastEventListener,
          LazyForwardingEventListener {
            if (InternalLeakCanary.formFactor == TV) TvEventListener else NotificationEventListener
          },
          when {
              RemoteWorkManagerHeapAnalyzer.remoteLeakCanaryServiceInClasspath ->
                RemoteWorkManagerHeapAnalyzer
              WorkManagerHeapAnalyzer.workManagerInClasspath -> WorkManagerHeapAnalyzer
              else -> BackgroundThreadHeapAnalyzer
          }
        ),
    

    5.10.1: RemoteWorkManagerHeapAnalyzer

      override fun onEvent(event: Event) {
        if (event is HeapDump) {
          val application = InternalLeakCanary.application
          val heapAnalysisRequest =
            OneTimeWorkRequest.Builder(RemoteHeapAnalyzerWorker::class.java).apply {
              val dataBuilder = Data.Builder()
                .putString(ARGUMENT_PACKAGE_NAME, application.packageName)
                .putString(ARGUMENT_CLASS_NAME, REMOTE_SERVICE_CLASS_NAME)
              setInputData(event.asWorkerInputData(dataBuilder))
              with(WorkManagerHeapAnalyzer) {
                addExpeditedFlag()
              }
            }.build()
          SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
          val workManager = WorkManager.getInstance(application)
          //入栈 执行workQueue
          workManager.enqueue(heapAnalysisRequest)
        }
    

    最终调用HeapAnalysis中的几个数据类 HeapAnalysisFailure HeapAnalysisSuccess,里面的toString()方法就是拼接的 我们在LeakCanary中看到的错误记录.

    摘要部分代码

    data class HeapAnalysisFailure(
      override val heapDumpFile: File,
      override val createdAtTimeMillis: Long,
      override val dumpDurationMillis: Long = DUMP_DURATION_UNKNOWN,
      override val analysisDurationMillis: Long,
      /**
       * An exception wrapping the actual exception that was thrown.
       */
      val exception: HeapAnalysisException
    ) : HeapAnalysis() {
    
      override fun toString(): String {
        return """====================================
    HEAP ANALYSIS FAILED
    
    You can report this failure at https://github.com/square/leakcanary/issues
    Please provide the stacktrace, metadata and the heap dump file.
    ====================================
    STACKTRACE
    
    $exception====================================
    METADATA
    
    Build.VERSION.SDK_INT: ${androidSdkInt()}
    Build.MANUFACTURER: ${androidManufacturer()}
    LeakCanary version: ${leakCanaryVersion()}
    Analysis duration: $analysisDurationMillis ms
    Heap dump file path: ${heapDumpFile.absolutePath}
    Heap dump timestamp: $createdAtTimeMillis
    ===================================="""
      }
    

    5.10.2: WorkManagerHeapAnalyzer

    和5.10.1有些类似 步骤更少

      override fun onEvent(event: Event) {
        if (event is HeapDump) {
          val heapAnalysisRequest = OneTimeWorkRequest.Builder(HeapAnalyzerWorker::class.java).apply {
            setInputData(event.asWorkerInputData())
            addExpeditedFlag()
          }.build()
          SharkLog.d { "Enqueuing heap analysis for ${event.file} on WorkManager remote worker" }
          val application = InternalLeakCanary.application
          WorkManager.getInstance(application).enqueue(heapAnalysisRequest)
        }
      }
    

    5.10.3: BackgroundThreadHeapAnalyzer

    override fun onEvent(event: Event) {
        if (event is HeapDump) {
          heapAnalyzerThreadHandler.post {
            val doneEvent = AndroidDebugHeapAnalyzer.runAnalysisBlocking(event) { event ->
              InternalLeakCanary.sendEvent(event)
            }
            InternalLeakCanary.sendEvent(doneEvent)
          }
        }
      }
    

    以上: LeakCanary的依赖 监听 dump 及分析都基本上理清了.

    6 PlumberInstaller

    leakcanary.internal.PlumberInstaller

    另外加餐补充这个, 这个类的作用主要是反射调用不同版本不同手机厂商 对有些api是否支持到.

    主要针对不同机型 不同版本,有些特殊的场景会导致Leak的时候,在Activity销毁的时候手动置为null方便回收.

    AndroidLeakFixes.applyFixes(application)
    

    这个分析是在后台通过单一线程池执行的

     Executors.newSingleThreadScheduledExecutor
    

    举个例子,比如 这里面就有针对三星设备 且不是19到21之间的版本
    反射TextView中的mLastHoveredView字段

      override fun apply(application: Application) {
          if (MANUFACTURER != SAMSUNG || SDK_INT !in 19..21) {
            return
          }
    
          backgroundExecutor.execute {
            val field: Field
            try {
              field = TextView::class.java.getDeclaredField("mLastHoveredView")
              field.isAccessible = true
            } catch (ignored: Exception) {
              SharkLog.d(ignored) { "Could not fix the $name leak" }
              return@execute
            }
    
            application.onActivityDestroyed {
              try {
                field.set(null, null)
              } catch (ignored: Exception) {
                SharkLog.d(ignored) { "Could not fix the $name leak" }
              }
            }
          }
        }
      },
    

    LeakActivity

    leakcanary.internal.activity.LeakActivity

    我们打开金丝雀图标展示的就是这个Activity.

    导入.hprof文件

     private fun importHprof(fileUri: Uri) {
        try {
          contentResolver.openFileDescriptor(fileUri, "r")
            ?.fileDescriptor?.let { fileDescriptor ->
              val inputStream = FileInputStream(fileDescriptor)
              InternalLeakCanary.createLeakDirectoryProvider(this)
                .newHeapDumpFile()
                ?.let { target ->
                  inputStream.use { input ->
                    target.outputStream()
                      .use { output ->
                        input.copyTo(output, DEFAULT_BUFFER_SIZE)
                      }
                  }
                  InternalLeakCanary.sendEvent(
                    HeapDump(
                      uniqueId = UUID.randomUUID().toString(),
                      file = target,
                      durationMillis = -1,
                      reason = "Imported by user"
                    )
                  )
                }
            }
        } catch (e: IOException) {
          SharkLog.d(e) { "Could not imported Hprof file" }
        }
      }
    

    RequestStoragePermissionActivity

    主要就是申请权限使用的.

    以上就是整体的分析过程.

    • 从设计模式来看,使用到了工厂模式(Wacher和分析器)
    • 巧妙运用ContentProvider特性达到无侵入式 一行代码接入
    • 相比老版本,新增了RootView及Service的监测

    注意事项: 这个官方声明只能在debug模式.

    才疏学浅,欢迎探讨.

    相关文章

      网友评论

        本文标题:LeakCanary最新2.8.1版本源码 原理分析 [2022

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