栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

LeakCanary最新2.8.1版本源码 原理分析 [2022年初kotlin版]

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

LeakCanary最新2.8.1版本源码 原理分析 [2022年初kotlin版]

首先从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: 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中的一个接口,同时Application中维护了一个ArrayList

 @UnsupportedAppUsage
    private ArrayList mActivityLifecycleCallbacks =
            new ArrayList();
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 = 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 = appDefaultWatchers(application)

四大金刚正式登场

  fun appDefaultWatchers(
    application: Application,
    reachabilityWatcher: ReachabilityWatcher = objectWatcher
  ): List {
    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的集合 
  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  create(modelClass: Class): 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>()

反射创建

 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
  }

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,
  
  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 = 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,
  
  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模式.

以上就是整体分析.

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/716884.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号