LeakCanary 源码分析 #2 Fragment, Service, ViewModel

何言 2022年01月23日 683次浏览

LeakCanary 是一个检查内存泄漏的库。以下是官网中的定义:

LeakCanary is a memory leak detection library for Android.

相关网站:

LeakCanary (square.github.io)

square/leakcanary: A memory leak detection library for Android. (github.com)

本文是 LeakCanary 源码系列第二章,重点分析 FragmentAndViewModelWatcher 和 ServiceWatcher(第一章分析了整体结构和 ActivityWatcher)

上文连接:
LeakCanary 源码分析 #1

AppDefaultWatchers

上文我们分析了一遍 AppDefaultWatchers,这里主要是进行了四个 Watcher 的安装,我们已经分析了第一个,接下来分析 第二个和 第四个。

  fun appDefaultWatchers(
    application: Application,
    reachabilityWatcher: ReachabilityWatcher = objectWatcher
  ): List<InstallableWatcher> {
    return listOf(
        // Activity
      ActivityWatcher(application, reachabilityWatcher),
        // Fragment 和 ViewModel
      FragmentAndViewModelWatcher(application, reachabilityWatcher),
        // 跟 View
      RootViewWatcher(reachabilityWatcher),
        // Service
      ServiceWatcher(reachabilityWatcher)
    )
  }

FragmentAndViewModelWatcher

来到该对象,先看注释:

/**
 * Expects:
 * - Fragments (Support Library, Android X and AOSP) to become weakly reachable soon after they
 * receive the Fragment#onDestroy() callback.
 * - Fragment views (Support Library, Android X and AOSP) to become weakly reachable soon after
 * fragments receive the Fragment#onDestroyView() callback.
 * - Android X view models (both activity and fragment view models) to become weakly reachable soon
 * after they received the ViewModel#onCleared() callback.
 */

该类实现了 InstallableWatcher,因此会有 nstall()uninstall() 方法。

override fun install() {
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}

override fun uninstall() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}

就是注册一个 ActivityLifecycleCallbacks,来看看 lifecycleCallbacks 变量:

private val lifecycleCallbacks =

    object : Application.ActivityLifecycleCallbacks by noOpDelegate() { // 使用 noOpDelegate 可以不用写其他空方法
        // onCreate 方法时调用
      override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
      ) {
          // 遍历 fragmentDestroyWatchers 数组,然后调用该对象(对象是一个高阶函数类型)
        for (watcher in fragmentDestroyWatchers) {
          watcher(activity)
        }
      }
    }

下面是我们的重点,也就是 fragmentDestroyWatchers 变量:

private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
    // 可以看到是一个 (Activity) -> Unit 类型的高阶函数的列表
    val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()

    // 如果当前版本为 安卓 o 或以上就添加一个 AndroidOFragmentDestroyWatcher
    if (SDK_INT >= O) {
      fragmentDestroyWatchers.add(
        AndroidOFragmentDestroyWatcher(reachabilityWatcher)
      )
    }
    // 根据反射判断当前环境然后添加对应的 Watcher

    getWatcherIfAvailable(
      ANDROIDX_FRAGMENT_CLASS_NAME,//"androidx.fragment.app.Fragment"
      ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME, //"leakcanary.internal.AndroidXFragmentDestroyWatcher"
      reachabilityWatcher
    )?.let {
      fragmentDestroyWatchers.add(it)
    }

    getWatcherIfAvailable(
      ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,// StringBuilder("android.").append("support.v4.app.Fragment").toString()
      ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME, // "leakcanary.internal.AndroidSupportFragmentDestroyWatcher"
      reachabilityWatcher
    )?.let {
      fragmentDestroyWatchers.add(it)
    }
    // run 内联函数的值为最后一行的值
    fragmentDestroyWatchers
  }

让我们先来看看 getWatcherIfAvailable 方法:

// 判断类是否存在  
private fun classAvailable(className: String): Boolean {
    return try {
        // 反射拿 class 对象
      Class.forName(className)
      true
    } catch (e: Throwable) {
      // e is typically expected to be a ClassNotFoundException
      // Unfortunately, prior to version 25.0.2 of the support library the
      // FragmentManager.FragmentLifecycleCallbacks class was a non static inner class.
      // Our AndroidSupportFragmentDestroyWatcher class is compiled against the static version of
      // the FragmentManager.FragmentLifecycleCallbacks class, leading to the
      // AndroidSupportFragmentDestroyWatcher class being rejected and a NoClassDefFoundError being
      // thrown here. So we're just covering our butts here and catching everything, and assuming
      // any throwable means "can't use this". See https://github.com/square/leakcanary/issues/1662
        
        // 如果类不存在则会抛异常
      false
    }
  } 

private fun getWatcherIfAvailable(
    fragmentClassName: String,
    watcherClassName: String,
    reachabilityWatcher: ReachabilityWatcher
  ): ((Activity) -> Unit)? {

    // 判断两个类是否存在
    return if (classAvailable(fragmentClassName) &&
      classAvailable(watcherClassName)
    ) {
        // 存在的话通过反射实例化
      val watcherConstructor =
        Class.forName(watcherClassName).getDeclaredConstructor(ReachabilityWatcher::class.java)
      @Suppress("UNCHECKED_CAST")
      watcherConstructor.newInstance(reachabilityWatcher) as (Activity) -> Unit
    } else {
      null
    }
  }

可以看到这里就是判断类名是否存在,如果存在则实例化一个 watcher 出来,因此最初的 fragmentDestroyWatchers 的初始化过程如下:

  1. 如果版本大于安卓 o,则添加 AndroidOFragmentDestroyWatcher 对象
  2. 如果 "androidx.fragment.app.Fragment" 类存在,则添加 AndroidXFragmentDestroyWatcher 对象(前提是后者也存在)
  3. 如果 "android.support.v4.app.Fragment" 类存在,则添加 AndroidSupportFragmentDestroyWatcher 对象(前提是后者也存在)

接下来我们分别来看前两个 Watcher 对象,其中 ViewModel 的判断过程在第二个对象中。

第三个对象随着 support 的弃用 已经被弃用,具体内容和第一个没有什么差别,也是在 fragmentmanager 里注册 callback。

首先这三个对象都是 (Activity) -> Unit 类型的,因此我们可以从其 invoke 方法开始看

AndroidOFragmentDestroyWatcher

@SuppressLint("NewApi")
internal class AndroidOFragmentDestroyWatcher(
  private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {
  private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {

    override fun onFragmentViewDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) {
      val view = fragment.view
      if (view != null) {
          // 这里开始观察这个 fragmentView
        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
    ) {
        // 这里开始观察这个 fragment
      reachabilityWatcher.expectWeaklyReachable(
        fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
      )
    }
  }

    // install 的时候会调用,这里直接使用 安卓的 api 在 fragmentmanager 中注册一个 callback
  override fun invoke(activity: Activity) {
    val fragmentManager = activity.fragmentManager
    fragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
  }
}

AndroidXFragmentDestroyWatcher

internal class AndroidXFragmentDestroyWatcher(
  private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {

  private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {

    override fun onFragmentCreated(
      fm: FragmentManager,
      fragment: Fragment,
      savedInstanceState: Bundle?
    ) {
      ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
    }

    override fun onFragmentViewDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) {
        // 在 onFragmentViewDestroyed 的时候观察 view
      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
    ) {
        // 在 FragmentDestroyed 的时候观察这个 fragment
      reachabilityWatcher.expectWeaklyReachable(
        fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
      )
    }
  }

    // 需要是 FragmentActivity 才能获取 FragmentManager
  override fun invoke(activity: Activity) {
    if (activity is FragmentActivity) {
      val supportFragmentManager = activity.supportFragmentManager
        // 首先还是向 FragmentManager 注册回调
      supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
        
        // 这里是 viewmodel 的处理,下面重点分析
      ViewModelClearedWatcher.install(activity, reachabilityWatcher)
    }
  }
}

这里调用了 ViewModelClearedWatcher 的伴生对象方法 install,接下来来到 ViewModelClearedWatcher

internal class ViewModelClearedWatcher(
  storeOwner: ViewModelStoreOwner,
  private val reachabilityWatcher: ReachabilityWatcher
) : ViewModel() { // 首先本身是一个 ViewModel

  private val viewModelMap: Map<String, ViewModel>?

  init {
    // We could call ViewModelStore#keys with a package spy in androidx.lifecycle instead,
    // however that was added in 2.1.0 and we support AndroidX first stable release. viewmodel-2.0.0
    // does not have ViewModelStore#keys. All versions currently have the mMap field.
    viewModelMap = try {
        // 这里通过反射获取 viewModelStore 的 viewmodel 对象
      val mMapField = ViewModelStore::class.java.getDeclaredField("mMap")
      mMapField.isAccessible = true
      @Suppress("UNCHECKED_CAST")
      mMapField[storeOwner.viewModelStore] as Map<String, ViewModel>
    } catch (ignored: Exception) {
      null
    }
  }

  override fun onCleared() {
      // 在自己的 onCleared 周期到达时观察其他所有 ViewModel
    viewModelMap?.values?.forEach { viewModel ->
      reachabilityWatcher.expectWeaklyReachable(
        viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback"
      )
    }
  }

  companion object {
    fun install(
      storeOwner: ViewModelStoreOwner,
      reachabilityWatcher: ReachabilityWatcher
    ) {
      val provider = ViewModelProvider(storeOwner, object : Factory {
        @Suppress("UNCHECKED_CAST")
          // 将自己注册为一个 ViewModel
        override fun <T : ViewModel?> create(modelClass: Class<T>): T =
          ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
      })
      provider.get(ViewModelClearedWatcher::class.java)
    }
  }
}

ServiceWatcher

swapActivityThreadHandlerCallback 和 swapActivityManager

首先,里面还是有 install 和 uninstall 方法,但我们先不看,我们先看 ServiceWarcher 中的 swapActivityThreadHandlerCallback 和 swapActivityManager 方法:

// Class 对象
private val activityThreadClass by lazy { Class.forName("android.app.ActivityThread") }

// 通过反射 currentActivityThread 方法获取当前 activityThread (并不是一个线程,更不是主线程) 对象(其中有主线程的 handler 对象等)
private val activityThreadInstance by lazy {
    activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)!!
}  

private fun swapActivityThreadHandlerCallback(swap: (Handler.Callback?) -> Handler.Callback?) {
      // 通过反射获取 activityTrhead 中的 mH 变量,也就是 handler 对象。
    val mHField =
      activityThreadClass.getDeclaredField("mH").apply { isAccessible = true }
    val mH = mHField[activityThreadInstance] as Handler

    // 修改 handler 中的 callback 变量
    val mCallbackField =
      Handler::class.java.getDeclaredField("mCallback").apply { isAccessible = true }
    
    // 设置为 传入的 swap 高阶函数处理过的 handler
    val mCallback = mCallbackField[mH] as Handler.Callback?
    mCallbackField[mH] = swap(mCallback)
  }

然后是 swapActivityManager 方法:

  @SuppressLint("PrivateApi")
  private fun swapActivityManager(swap: (Class<*>, Any) -> Any) {
    val singletonClass = Class.forName("android.util.Singleton")
    val mInstanceField =
      singletonClass.getDeclaredField("mInstance").apply { isAccessible = true }

    val singletonGetMethod = singletonClass.getDeclaredMethod("get")

      // 不同安卓版本 的 ActivityManager 的变量格式不一样
    val (className, fieldName) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      "android.app.ActivityManager" to "IActivityManagerSingleton"
    } else {
      "android.app.ActivityManagerNative" to "gDefault"
    }

    val activityManagerClass = Class.forName(className)
    val activityManagerSingletonField =
      activityManagerClass.getDeclaredField(fieldName).apply { isAccessible = true }
    val activityManagerSingletonInstance = activityManagerSingletonField[activityManagerClass]

    // Calling get() instead of reading from the field directly to ensure the singleton is
    // created.
    val activityManagerInstance = singletonGetMethod.invoke(activityManagerSingletonInstance)

    val iActivityManagerInterface = Class.forName("android.app.IActivityManager")
      
      // 使用参数的高阶函数修改 WindowManager 后替换
    mInstanceField[activityManagerSingletonInstance] =
      swap(iActivityManagerInterface, activityManagerInstance!!)
  }

install 和 uninstall

然后我们来到 install 方法:

  override fun install() {
    checkMainThread()
    check(uninstallActivityThreadHandlerCallback == null) {
      "ServiceWatcher already installed"
    }
    check(uninstallActivityManager == null) {
      "ServiceWatcher already installed"
    }
    try {
      swapActivityThreadHandlerCallback {
          // 1…
      }
      swapActivityManager{
          // ……
      }
    } catch (ignored: Throwable) {
      SharkLog.d(ignored) { "Could not watch destroyed services" }
    }
  }
       

  override fun uninstall() {
    checkMainThread() // 检查 Main
    uninstallActivityManager?.invoke() // 调用 之前设置的 取消 Hook 方法
    uninstallActivityThreadHandlerCallback?.invoke() // 同上
    uninstallActivityManager = null
    uninstallActivityThreadHandlerCallback = null
  }

install 中的 两个 hook

可以看到 install 主体就是调用了我们的两个 swap 方法,接下来我们一个一个看

      swapActivityThreadHandlerCallback { mCallback ->
         // unstall 之后需要使用 swap 替换回原来的 callback
        uninstallActivityThreadHandlerCallback = {
          swapActivityThreadHandlerCallback {
            mCallback
          }
        }
        // lamda 的值
        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
          }

          // 如果是 STOP SERVICE 的事件,则根据 IBinder 对象获取 service 对象,然后观察
          if (msg.what == STOP_SERVICE) {
            val key = msg.obj as IBinder
            activityThreadServices[key]?.let {
                // 调用 onServicePreDestory 方法
              onServicePreDestroy(key, it)
            }
          }
          // 还需要走原逻辑
          mCallback?.handleMessage(msg) ?: false
        }
      }

接下来是 swapActivityManager:

      swapActivityManager { activityManagerInterface, activityManagerInstance ->
        // 同上,在 unstall 之后需要替换回原 was
        uninstallActivityManager = {
          swapActivityManager { _, _ ->
            activityManagerInstance
          }
        }
         
        // 动态代理
        Proxy.newProxyInstance(
          activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
        ) { _, method, args ->
           // 这里方法名为 "serviceDoneExecuting"
          if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
            val token = args!![0] as IBinder
              // 在调用该方法时调用 onServiceDestroyed 方法
            if (servicesToBeDestroyed.containsKey(token)) {
              onServiceDestroyed(token)
            }
          }
          try {
            if (args == null) {
              method.invoke(activityManagerInstance)
            } else {
              method.invoke(activityManagerInstance, *args)
            }
          } catch (invocationException: InvocationTargetException) {
            throw invocationException.targetException
          }
        }
      }

通过反射,Hook 了两个地方,一个是 主线程 handler 收到 STOP_SERVICE 事件的地方,然后调用了 onServicePreDestroy,第二个是 ActivityServiceManager 中的 serviceDoneExecuting 方法(具体可以自己学习,主要是该方法用于通知 Service 被销毁,也就是该方法调用后 Service 已经确认被销毁),然后调用 onServiceDestroyed 方法,这里我们来到这两个方法:

onServicePreDestroy 和 onServiceDestroyed

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

  private fun onServicePreDestroy(
    token: IBinder,
    service: Service
  ) {
      // 将 service 存到 map 中(使用 WeakHashMap 不会影响 GC)
      // 之所以需要存一下,是因为 onServiceDestroyed 中没有 Service 对象。因此需要在收到事件时将 IBinder 与 Service 对应起来
    servicesToBeDestroyed[token] = WeakReference(service)
  }

  private fun onServiceDestroyed(token: IBinder) {
      // 在已经确定销毁 Service 后,开始观察 Service 是否被回收
    servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
      serviceWeakReference.get()?.let { service ->
        reachabilityWatcher.expectWeaklyReachable(
          service, "${service::class.java.name} received Service#onDestroy() callback"
        )
      }
    }
  }

至此 ServiceWatcher 分析完毕