LeakCanary核心机制学习

read the fucking source code

前言

本文不包含分析LeakCanary所使用的haha库的代码.

LeakCanary 官网

本文基于:leakcanary-android:2.7

简单的使用仅是一句话,连初始化代码都不需要你写.

dependencies {
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
}

LeakCanary初始化分析

在这里插入图片描述

上图便是leakCanary工程目录,而初始化代码位于leakcanary-android-process.
其清单文件如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.squareup.leakcanary.objectwatcher" >

    <uses-sdk android:minSdkVersion="14" />

    <application>
    	<!--很巧妙的利用利用provider进行初始化-->
        <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>

这里补充一个知识点 AMS初始一个app的时候先调用Provider.onCreate在调用Application.onCreate.
又让我从LeakCanary学来的奇淫技巧.
如果你想知道为什么可参考:
Application.onCreate 、ContentProvider.onCreate 、 Activity.onCreate 的调用顺序研究

//AppWatcherInstaller.kt
internal sealed class AppWatcherInstaller : ContentProvider() {
  //内部类巧妙的运用,可以瞬间构造两个不同的provider,可以拿来切换或者测试等	
  internal class MainProcess : AppWatcherInstaller()

  internal class LeakCanaryProcess : AppWatcherInstaller()

  override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    AppWatcher.manualInstall(application)
    return true
  }
//ObjectWatcher.kt
class ObjectWatcher constructor(
  private val clock: Clock,
  //注意下这个参数,Executor很明显就是jdk类,用于封装线程调度
  private val checkRetainedExecutor: Executor,
  private val isEnabled: () -> Boolean = { true }
)

//AppWatcher.kt
object AppWatcher {

//ObjectWatcher对象具体后面将.我们首先观察一个属性checkRetainedExecutor
val objectWatcher = ObjectWatcher(
   clock = { SystemClock.uptimeMillis() },
   checkRetainedExecutor = {
    //internal val mainHandler by lazy { Handler(Looper.getMainLooper()) }
    //这里拿的android主线的handler
    //为什么这里拿主线程是有一定原因的后文再讲
     mainHandler.postDelayed(it, retainedDelayMillis)
   },
   isEnabled = { true }
 )
 

   fun manualInstall(
    application: Application,
    retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
    watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
  ) {
    //...略
    //注册一些监听这里先不深究,讲到时在做分析
    LeakCanaryDelegate.loadLeakCanary(application)

    //我们在看下这个集合
    watchersToInstall.forEach {
      it.install()
    }
  }
  
   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)
    )
  }	
}  

上面将四个集合对象调用install便完成了初始化.

ActivityWatcher

ActivityWatcher用于监控Activity相关的泄露.在了解之前先要补充一个小知识点.

ReferenceQueue妙用

ReferenceQueue被相关引用我们可知道那些对象被回收.


public class JavaMain {
    static String smg = new String("nihao");

    public static void main(String[] args) throws InterruptedException {

        ReferenceQueue<String> queue = new ReferenceQueue<>();
        //WeakReference对象被回收时,会将reference放入queue中
        Reference<String> reference = new WeakReference<>(smg, queue);
        
        Reference<? extends String> poll = queue.poll();
	    //输出null,因为对象被smg引用
	    System.out.println(poll);
        smg = null;
       
        //执行Gc,在android请用Runtime.getRuntime().gc();具体原因后文讲解
        System.gc();
        TimeUnit.SECONDS.sleep(1);
        //输出java.lang.ref.WeakReference@15db9742
         poll = queue.poll();
        System.out.println(poll);
    }
}

上面是一个小例子,请务必理解.另外如果WeakReference持有的是常量池的引用,是不会被回收的.如下:

public class JavaMain {
    //注意原来是new String("nihao")
    //smg指向常量池nihao
    static String smg = "nihao";

    public static void main(String[] args) throws InterruptedException {

        ReferenceQueue<String> queue = new ReferenceQueue<>();
        Reference<String> reference = new WeakReference<>(smg, queue);
        Reference<? extends String> poll = queue.poll();
        //输出null
        System.out.println(poll);
        smg = null;
        //执行Gc,在android请用Runtime.getRuntime().gc();具体原因后文讲解
        System.gc();
        TimeUnit.SECONDS.sleep(1);
       
        poll = queue.poll();
        //输出null.常量池对象不轻易回收
        System.out.println(poll);
    }
}

ActivityWatcher的核心思想是在ActivityDestroy时,将Activity放入一个WeakReference中,而WeakReference会传入一个ReferenceQueue,在等候一定时间后判断ReferenceQueue是否有了新元素.

ActivityWatcher

//ActivityWatcher.kt
class ActivityWatcher(
  private val application: Application,
  private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {

  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityDestroyed(activity: Activity) {
    	//利用Application对象注册Activity的destory回调.
    	//reachabilityWatcher指向AppWatcher.objectWatcher
        reachabilityWatcher.expectWeaklyReachable(
          activity, "${activity::class.java.name} received Activity#onDestroy() callback"
        )
      }
    }
  //初始化代码会调用
  override fun install() {
    application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
  }

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

class ObjectWatcher constructor(
 private val clock: Clock,
  private val checkRetainedExecutor: Executor,//指向main线程哦
  private val isEnabled: () -> Boolean = { true }){

  //放入要检测泄露的对象,和queue配合检测泄露,如果queue.pool返回对象时需要删除watchedObjects引用
  private val watchedObjects = mutableMapOf<String, KeyedWeakReference>()
  //queue存储要检测的休闲,和watchedObjects合作检测泄露
  private val queue = ReferenceQueue<Any>()

  @Synchronized override fun expectWeaklyReachable(
    watchedObject: Any,
    description: String
  ) {
  
    if (!isEnabled()) {
      return
    }
    
    //循环queue.pool函数直到返回null,期间同时清理能返回数据的watchedObjects对象
    removeWeaklyReachableObjects()

    val key = UUID.randomUUID()
      .toString()
    val watchUptimeMillis = clock.uptimeMillis()
	//将当前Activity放入引用对象中,注意这里传入了queue
    val reference =
      KeyedWeakReference(watchedObject, key, description, watchUptimeMillis, queue)
    
	//放入一个数组中
    watchedObjects[key] = reference
    //checkRetainedExecutor是主线程哦.execute会将任务丢到队列中,那么会延迟执行,
    //为什么checkRetainedExecutor要是主线程?因为Activity调用destroy不会马上回收,
    //android会在destroy返回后会做一些清理在回收
    checkRetainedExecutor.execute {
    //往下分析
      moveToRetained(key)
    }
  }
  private fun removeWeaklyReachableObjects() {
    //比较简单,queue.pool返回了对象,那么证明对象被回收,watchedObjects也就没必要保存监控对象
    var ref: KeyedWeakReference?
    do {
      ref = queue.poll() as KeyedWeakReference?
      if (ref != null) {
        watchedObjects.remove(ref.key)
      }
    } while (ref != null)
  }
	
  

}

上文会将一个事件丢入main线程然后等候下次调度moveToRetained,这时基本Activity已经被回收

   private fun moveToRetained(key: String) {
  	//移除被回收对象
    removeWeaklyReachableObjects()
    
    val retainedRef = watchedObjects[key]
    //如果removeWeaklyReachableObjects没有移除retainedRef 那么证明还没有回收
    if (retainedRef != null) {
      retainedRef.retainedUptimeMillis = clock.uptimeMillis()
      //onObjectRetainedListeners在LeakCanaryDelegate.loadLeakCanary(application)被设置
      onObjectRetainedListeners.forEach { it.onObjectRetained() }
    }
  }	
//InternalLeakCanary.kt
//这里继承两个接口:
//				(Application) -> Unit 
//				OnObjectRetainedListener
internal object InternalLeakCanary : (Application) -> Unit, OnObjectRetainedListener {
  //运行到这
  override fun onObjectRetained() = scheduleRetainedObjectCheck()

  fun scheduleRetainedObjectCheck() {
  	//视为true即可
    if (this::heapDumpTrigger.isInitialized) {
      //heapDumpTrigger为HeapDumpTrigger,再次严禁的确认对象是否没有被释放
      heapDumpTrigger.scheduleRetainedObjectCheck()
    }
  }
}
//HeapDumpTrigger.kt
 fun scheduleRetainedObjectCheck(
    delayMillis: Long = 0L
  ) {
    val checkCurrentlyScheduledAt = checkScheduledAt
    if (checkCurrentlyScheduledAt > 0) {
      return
    }
    checkScheduledAt = SystemClock.uptimeMillis() + delayMillis
   	//backgroundHandler是一个子线程
    backgroundHandler.postDelayed({
      checkScheduledAt = 0
      checkRetainedObjects()
    }, delayMillis)
  }
 private fun checkRetainedObjects() {
   		//再次严禁的确认是否泄漏,
   		//获取存活数量
        var retainedReferenceCount = objectWatcher.retainedObjectCount
		
        if (retainedReferenceCount > 0) {
          //触发gc后在获取一次存活数量
          gcTrigger.runGc()
          retainedReferenceCount = objectWatcher.retainedObjectCount
        }
        //...略
}        
 object Default : GcTrigger {
    override fun runGc() {
      // Code taken from AOSP FinalizationTest:
      // https://android.googlesource.com/platform/libcore/+/master/support/src/test/java/libcore/
      // java/lang/ref/FinalizationTester.java
      // System.gc() does not garbage collect every time. Runtime.gc() is
      // more likely to perform a gc.
      //这里英文注释解释的很好,System.gc() 并不会每次都会执行gc,Runtime.gc()更加可能执行
      Runtime.getRuntime()
        .gc()
      enqueueReferences()
      System.runFinalization()
    }

    private fun enqueueReferences() {
      // Hack. We don't have a programmatic way to wait for the reference queue daemon to move
      // references to the appropriate queues.
      try {
        Thread.sleep(100)
      } catch (e: InterruptedException) {
        throw AssertionError()
      }
    }
  }

在确认泄漏后我们不在分析,我们看看其他泄漏是怎么检测的

FragmentAndViewModelWatcher

class FragmentAndViewModelWatcher(
  private val application: Application,
  private val reachabilityWatcher: ReachabilityWatcher
) : InstallableWatcher {

  private val fragmentDestroyWatchers: List<(Activity) -> Unit> = run {
    val fragmentDestroyWatchers = mutableListOf<(Activity) -> Unit>()

   //略这里 AndroidXFragmentDestroyWatcher放入fragmentDestroyWatchers
	
    fragmentDestroyWatchers
  }

  private val lifecycleCallbacks =
    object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
      override fun onActivityCreated(
        activity: Activity,
        savedInstanceState: Bundle?
      ) {
      //注意这里调用oncreate的时候放入一个观察
      //fragmentDestroyWatchers存放AndroidXFragmentDestroyWatcher
        for (watcher in fragmentDestroyWatchers) {
          //调用AndroidXFragmentDestroyWatcher.invoke.
          //	
          watcher(activity)
        }
      }
    }

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

  override fun uninstall() {
    application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
  } 
}
//AndroidXFragmentDestroyWatcher.kt
internal class AndroidXFragmentDestroyWatcher(
  private val reachabilityWatcher: ReachabilityWatcher
) : (Activity) -> Unit {

  override fun invoke(activity: Activity) {
    if (activity is FragmentActivity) {
      val supportFragmentManager = activity.supportFragmentManager
      //registerFragmentLifecycleCallbacks可以监听到每个fragment的添加和实例
      supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
      //viewModel相关,先暂时放着	
      ViewModelClearedWatcher.install(activity, reachabilityWatcher)
    }
  }
  
  private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() {

    override fun onFragmentCreated(
      fm: FragmentManager,
      fragment: Fragment,
      savedInstanceState: Bundle?
    ) {
      //viewmodel相关,先跳过
      ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
    }

    override fun onFragmentViewDestroyed(
      fm: FragmentManager,
      fragment: Fragment
    ) {
      val view = fragment.view
      if (view != null) {
      	//检测view是否被持有,原理同Activity,这里不在重复讲解
        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是否被持有,原理同Activity.这里不在重复讲解
      reachabilityWatcher.expectWeaklyReachable(
        fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
      )
    }
  }
}

ViewModelClearedWatcher

上一小节我们看到在fragment的create函数调用 ViewModelClearedWatcher.install(fragment, reachabilityWatcher)进行监控viewmodel的泄露.
请务必了解viewmodel基础知识:

ViewModel 源码分析

internal class ViewModelClearedWatcher(
  storeOwner: ViewModelStoreOwner,
  private val reachabilityWatcher: ReachabilityWatcher
) : ViewModel() {

  private val viewModelMap: Map<String, ViewModel>?

  init {
	  //ViewModelStore内部有一个mMap对象,mMap存放所有的viewmodel
      val mMapField = ViewModelStore::class.java.getDeclaredField("mMap")
      mMapField.isAccessible = true
	 //获取fragment的ViewModelStoreOwner实例,通过实例获得这个mMap对象
	 //从而得到所有的viewmodel
      mMapField[storeOwner.viewModelStore] as Map<String, ViewModel>
    } catch (ignored: Exception) {
      null
    }
  }

  override fun onCleared() {
  	//开始回收viewmodel
  	//遍历所有的viewmodel然后检查是否泄漏
    viewModelMap?.values?.forEach { viewModel ->
      reachabilityWatcher.expectWeaklyReachable(
        viewModel, "${viewModel::class.java.name} received ViewModel#onCleared() callback"
      )
    }
  }

  companion object {
    fun install(
      storeOwner: ViewModelStoreOwner,
      reachabilityWatcher: ReachabilityWatcher
    ) {
      //这里注意传入的factory,不过传入什么都是创建ViewModelClearedWatcher对象
      val provider = ViewModelProvider(storeOwner, object : Factory {
        override fun <T : ViewModel?> create(modelClass: Class<T>): T =
          ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
      })
      //ViewModelClearedWatcher是一个间谍viewmodel,主要是为了监听oncleared回调
      provider.get(ViewModelClearedWatcher::class.java)
    }
  }
}

ServiceWatcher

监控ServiceDestroy代码可能略复杂.设计反射,和service启动流程.需要知道一些插件化知识.
下文可能需要基础的handler知识,可参阅博主:
handler相关知识

知识储备

我们四大组件的创建和销毁都会从AMS通过Binder(跨进程IPC方式)传到我们AppActivityThread.mh处理.

而mh是我们的是一个Handler,于是乎我们可以反射拿到mh,然后给Handler设置一个mCallback对象即可拦截所有的AMS消息.mCallback返回false会继续交给handler处理.

public final class ActivityThread {
	    final H mH = new H();
	private class H extends Handler {
	}
}

在这里插入图片描述
我们设置mCallback

在这里插入图片描述
我们最后看下LeakCanary相关代码


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

 //ActivityThread有一静态个属性currentActivityThread,保存自己的实例
 private val activityThreadInstance by lazy {	
    activityThreadClass.getDeclaredMethod("currentActivityThread").invoke(null)!!
  }
  	
 private fun swapActivityThreadHandlerCallback(swap: (Handler.Callback?) -> Handler.Callback?) {
    //activityThreadClass为Class.forName("android.app.ActivityThread")
    val mHField =
      activityThreadClass.getDeclaredField("mH").apply { isAccessible = true }
    //获取属性,这里mHField[xxxx]是kotlin语法不比困惑  
    val mH = mHField[activityThreadInstance] as Handler
	//找到Handler.mCallback
    val mCallbackField =
      Handler::class.java.getDeclaredField("mCallback").apply { isAccessible = true }
    //获取mCallback实例
    val mCallback = mCallbackField[mH] as Handler.Callback?
    //替换成自己的Handler.Callback,内部会转发到原始mCallback
    mCallbackField[mH] = swap(mCallback)
  }

service还有一个相关的函数ActivityManagerProxy.serviceDoneExecuting,
当service创建完成(回调oncreate之后)后,回调用ActivityManagerProxy.serviceDoneExecuting.当service被销毁后(AMS下发消息,且回调onDestroy后)回调ActivityManagerProxy.serviceDoneExecuting

Service启动过程源码阅读

所以我们有两个hook点可以用来检测被销毁.

//因为都是简单操作,读者可自行类别上文swapActivityThreadHandlerCallback
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")

    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")
    mInstanceField[activityManagerSingletonInstance] =
      swap(iActivityManagerInterface, activityManagerInstance!!)
  }

另外最后补充一个小点ActivityThreadmServices保存了所有app的service

//ActivityThread.java
class ActivityThread{
  
 final ArrayMap<IBinder, Service> mServices
            = new ArrayMap<IBinder, Service>();
}

我们结合以下在看ServiceWatcher就很简单.

//ServiceWatcher.java
  //存放要观察的service
  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)!!
  }
  //存放所有app的service	
  private val activityThreadServices by lazy {
    val mServicesField =
      activityThreadClass.getDeclaredField("mServices").apply { isAccessible = true }

    @Suppress("UNCHECKED_CAST")
    mServicesField[activityThreadInstance] as Map<IBinder, Service>
  }
  
override fun install() {
    checkMainThread()
    
    try {
    
      swapActivityThreadHandlerCallback { mCallback ->
        uninstallActivityThreadHandlerCallback = {
          swapActivityThreadHandlerCallback {
            mCallback
          }
        }
        Handler.Callback { msg ->
  		  //回调stopservice函数	
          if (msg.what == STOP_SERVICE) {
            val key = msg.obj as IBinder
            //activityThreadServices一定不为空
            //所以调用onServicePreDestroy,内部会将service放入servicesToBeDestroyed
            //后面会回调serviceDoneExecuting函数
            activityThreadServices[key]?.let {
              onServicePreDestroy(key, it)
            }
          }
          mCallback?.handleMessage(msg) ?: false
        }
      }
      //servicesToBeDestroyed相关hook
      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
            //servicesToBeDestroyed会在创建的时候回调,也会在销毁的时候回调
            //servicesToBeDestroyed所在上面销毁的时候加入元素.
            //所以servicesToBeDestroyed包含要检测的service直接调用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
          }
        }
      }
    } catch (ignored: Throwable) {
      SharkLog.d(ignored) { "Could not watch destroyed services" }
    }
  }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值