LeakCanary 源码分析 #2 Fragment, Service, ViewModel
LeakCanary 是一个检查内存泄漏的库。以下是官网中的定义:
LeakCanary is a memory leak detection library for Android.
相关网站:
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 的初始化过程如下:
- 如果版本大于安卓 o,则添加 AndroidOFragmentDestroyWatcher 对象
- 如果 "androidx.fragment.app.Fragment" 类存在,则添加 AndroidXFragmentDestroyWatcher 对象(前提是后者也存在)
- 如果 "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 分析完毕