注册

Andorid进阶一:LeakCanary源码分析,从头到尾搞个明白

"内存优化会不会?知道怎么定位内存问题吗?"面试官和蔼地坐在小会议室的一侧,亲切地问有些拘谨地小张。

"就是...那个,用LeakCanary 检测一下泄漏,然后找到对应泄漏的地方,把错误的代码改一下,没回收的引用回收掉,优化下长短生命周期线程的依赖关系吧"

"那你了解LeakCanary 分析内存泄漏的原理吗?"

"不好意思,平时没有注意去看过" 小张心想:面试怎么老问这个,我只是个普通的菜鸟啊。

前言

app性能优化总是开发中必不可少的一环,而其中内存优化又是重点之一。内存泄漏带来的内存溢出崩溃,内存抖动带来的卡顿不流畅。都在切切实实地影响着用户的体验。我们常常会使用LeakCanary来定位内存泄漏问题。也是时候来探索一下人家是怎么实现的了。

名词理解

hprof : hprof 文件是 Java 的 内存快照文件(Heap Profile 的缩写),格式后缀为 .hprof,在leakCanary 中用于内存保存分析 WeakReference : 弱引用,当一个对象仅仅被weak reference(弱引用)指向, 而没有任何其他strong reference(强引用)指向的时候, 如果这时GC运行, 那么这个对象就会被回收,不论当前的内存空间是否足够,这个对象都会被回收。在leakCanary 中用于监测该回收的无用对象是否被释放。 curtains:Square 的另一个开源框架,Curtains 提供了用于处理 Android 窗口的集中式 API。在leakCanary中用于监测window rootView 在detached 后的内存泄漏。

目录

本文主要从以下几点入手分析

  1. 如何在项目中使用 LeakCanary工具
  2. 官方原理说明
  3. 默认如何监听Activity ,view ,fragment 和 viewmodel
  4. Watcher.watch(object) 如何监听内存泄漏
  5. 如何保存内存泄漏内存文件
  6. 如何分析内存泄漏文件
  7. 展示内存泄漏堆栈到ui中 不支持在 Docs 外粘贴 block

一,怎么用?

查看官网文档 可以看出使用方法非常简单,基础用法只需要添加相关依赖就行

//(1)
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.7'
复制代码

debugImplementation 只在debug模式的编译和最终的debug apk打包时有效 注(1):标注的代码中用了一行就实现了初始化,怎么做到的呢? 通过查看源码可以看到,leakcanary 通过 ContentProvider 进行初始化,在AppWatcherInstaller 类的oncreate方法中调用了真正的初始化代码AppWatcher.manualInstall(application)。在AndroidManifest.xml中注册该provider,注册的ContentProvider会在 application 启动的时候自动回调 oncreate方法。

internal sealed class AppWatcherInstaller : ContentProvider() {
/**[MainProcess] automatically sets up the LeakCanary code that runs in the main app process. */
// (1)
internal class MainProcess : AppWatcherInstaller()
internal class LeakCanaryProcess : AppWatcherInstaller()
override fun onCreate(): Boolean {
val application = context!!.applicationContext as Application
///(2)
AppWatcher.manualInstall(application)
return true
}
//...
}
复制代码

说明一下源码中的数字标注

  1. 代码中定义了两个内部类继承自 AppWatcherInstaller。当用户额外依赖 leakcanary-android-process 模块的时候,自动在 process=":leakcanary" 也注册该provider。

代码参见 leakcanary-android-process 模块中的AndroidManifest.xml

  1. 这是真正的初始化代码注册入口

二,官方阐述

官方说明

本小节来自于官方网站的工作原理说明精简 安装 LeakCanary 后,它会通过 4 个步骤自动检测并报告内存泄漏:

  1. 检测被持有的对象

    LeakCanary 挂钩到 Android 生命周期以自动检测活动和片段何时被销毁并应进行垃圾收集。这些被销毁的对象被传递给一个ObjectWatcher,它持有对它们的弱引用。 可以主动观察一个不再需要的对象比如一个 dettached view 或者 已经销毁的 presenter

AppWatcher.objectWatcher.watch(myDetachedView, "View was detached")
复制代码

如果ObjectWatcher等待 5 秒并运行垃圾收集后没有清除持有的弱引用,则被监视的对象被认为是保留的,并且可能会泄漏。LeakCanary 将此记录到 Logcat:

D LeakCanary: Watching instance of com.example.leakcanary.MainActivity
(Activity received Activity#onDestroy() callback)

... 5 seconds later ...

D LeakCanary: Scheduling check for retained objects because found new object
retained
复制代码
  1. Dumping the heap 转储堆信息到文件中

    当保留对象的数量达到阈值时,LeakCanary 将 Java 内存快照 dumping 转储到 Android 文件系统上的.hprof文件(堆内存快照)中。转储堆会在短时间内冻结应用程序,并展示下图的吐司: img

  2. 分析堆内存

    LeakCanary使用Shark解析.hprof文件并在该内存快照文件中定位被保留的泄漏对象。 对于每个保留对象,LeakCanary 找到该对象的引用路径,该引用阻止了垃圾收集器对它的回收。也就是泄漏跟踪。 LeakCanary为每个泄漏跟踪创建一个签名 (对持有的引用属性进行相加做sha1Hash),并将具有相同签名的泄漏(即由相同错误引起的泄漏)组合在一起。如何创建签名和通过签名分组有待后文分析。

  3. 分类内存泄漏

    LeakCanary 将它在您的应用中发现的泄漏分为两类:Application Leaks (应用程序泄漏)和Library Leaks(库泄漏)。一个Library Leaks是由已知的第三方库导致的,你没有控制权。这种泄漏正在影响您的应用程序,但不幸的是,修复它可能不在您的控制范围内,因此 LeakCanary 将其分离出来。 这两个类别分开Logcat结果中打印:

====================================
HEAP ANALYSIS RESULT
====================================
0 APPLICATION LEAKS
====================================
1 LIBRARY LEAK
...
┬───
│ GC Root: Local variable in native code

...
复制代码

LeakCanary在其泄漏列表展示中会将其用Library Leak 标签标记: img LeakCanary 附带一个已知泄漏的数据库,它通过引用名称的模式匹配来识别。例如:

Leak pattern: instance field android.app.Activity$1#this$0
Description: Android Q added a new IRequestFinishCallback$Stub class [...]
┬───
│ GC Root: Global variable in native code

├─ android.app.Activity$1 instance
│ Leaking: UNKNOWN
│ Anonymous subclass of android.app.IRequestFinishCallback$Stub
│ ↓ Activity$1.this$0
│ ~~~~~~
╰→ com.example.MainActivity instance
复制代码

Library Leaks 通常我们都无力对齐进行修复 您可以在AndroidReferenceMatchers类中查看已知泄漏的完整列表。如果您发现无法识别的 Android SDK 泄漏,请报告。您还可以自定义已知库泄漏的列表

三,监测activity,fragment,rootView和viewmodel

前面提到初始化的代码如下,所以我们 查看manualInstall 的内部细节。

///初始化代码
AppWatcher.manualInstall(application)

///AppWatcher 的 manualInstall 代码
@JvmOverloads
fun manualInstall(
application: Application,
retainedDelayMillis: Long = TimeUnit.SECONDS.toMillis(5),
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)
) {
//*******检查是否为主线程********/
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) {
LogcatSharkLog.install()
}
// Requires AppWatcher.objectWatcher to be set
///(2)
LeakCanaryDelegate.loadLeakCanary(application)
///(1)
watchersToInstall.forEach {
it.install()
}
}
复制代码

AppWatcher 作为Android 平台使用 ObjectWatcher 封装的api中心。自动安装配置默认的监听。 以上代码关键的地方用数字标出了

(1)Install 默认的监听观察

标注(1)处的代码执行了 InstallableWatcher 的 install 操作,在调用的时候并没有传递 watchersToInstall 参数,所以使用的是 appDefaultWatchers(application)。该处代码在下面,提供了 四个默认监听的Watcher

fun appDefaultWatchers(
application: Application,
///(1.1)
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
return listOf(
///(1.2)
ActivityWatcher(application, reachabilityWatcher),
///(1.3)
FragmentAndViewModelWatcher(application, reachabilityWatcher),
///(1.4)
RootViewWatcher(reachabilityWatcher),
///(1.5)
ServiceWatcher(reachabilityWatcher)
)
}
复制代码

用数字标出的四个我们逐个分析

(1.1) reachabilityWatcher 参数

标注(1.1)处的代码是一个 ReachabilityWatcher 参数,reachabilityWatcher 在后续的四个实例创建时候都有用到,代码中可以看到reachabilityWatcher实例是AppWatcher 的成员变量:objectWatcher,对应的实例化代码如下。

/**
* The [ObjectWatcher] used by AppWatcher to detect retained objects.
* Only set when [isInstalled] is true.
*/

val objectWatcher = ObjectWatcher(
clock = { SystemClock.uptimeMillis() },
checkRetainedExecutor = {
check(isInstalled) {
"AppWatcher not installed"
}
mainHandler.postDelayed(it, retainedDelayMillis)
},
isEnabled = { true }
)
复制代码

可以看到objectWatcher 是一个 ObjectWatcher对象,该对象负责检测持有对象的泄漏情况,会在第三小节进行分析。 回到 ActivityWatcher 实例的创建,继续往下看标注的代码

(1.2)ActivityWatcher 实例 完成Activity 实例的监听

回到之前,标注(1.2)处的代码创建了ActivityWatcher实例,并在install 的时候安装,查看ActivityWatcher 类的源码,看监听Activity泄漏是怎么实现的

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

private val lifecycleCallbacks =
//(1.2.1) 通过动态代理,构造出生命周期回调的实现类
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityDestroyed(activity: Activity) {
//(1.2.3)
reachabilityWatcher.expectWeaklyReachable(
activity, "${activity::class.java.name} received Activity#onDestroy() callback"
)
}
}

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

override fun uninstall() {
application.unregisterActivityLifecycleCallbacks(lifecycleCallbacks)
}
复制代码

(1.2.1) lifecycleCallbacks 实例

标注(1.2.1)处的代码创建了ActivityLifecycleCallbacks实例,该实例实现了Application.ActivityLifecycleCallbacks。通过 by ``*noOpDelegate*``() ,利用动态代理实现了其他回调方法,感兴趣的可以查看 noOpDelegate 的源码

(1.2.2) activity监听器的 install 方法

标注(1.2.2)处的代码是初始化的主要代码,该方法很简单,就是在application的 中注册 lifecycleCallbacks,在activity 被destroy 的时候会走到其中实现的方法

(1.2.3) 监听activity 的 onActivityDestroyed 回调

标注(1.2.3)处的代码是初始化的主要代码,在 activity被销毁的时候,回调该方法,在其中检查该实例是否有泄漏,调用AppWatcher.objectWatcher. expectWeaklyReachable 方法,在其中完成activity的泄漏监测。 这时候又回到了 1.1 提到的 ObjectWatcher源码,相关分析看第四节 。

(1.2-end)Activity监测相关总结

这样ActivityInstaller 就看完了,了解了Activity 的初始化代码以及加入监听的细节。总结一下分为如下几步:

  1. 调用ActivityInstaller.install 初始化方法
  2. 在Application 注册ActivityLifecycleCallbacks
  3. 在所有activity onDestroy的时候调用ObjectWatcher的 expectWeaklyReachable方法,检查过五秒后activity对象是否有被内存回收。标记内存泄漏。下一节分析。
  4. 检测到内存泄漏的后续操作。后文分析。

(1.3) FragmentAndViewModelWatcher 监测 Fragment 和Viewodel实例

(1.3)处是创建了 FragmentAndViewModelWatcher 实例。监测fragment和viewmodel的内存泄漏。

该类实现了 SupportFragment和 androidxFragment以及androidO 的兼容,作为sdk开发来说,这种 兼容方式可以学习一下。

private val lifecycleCallbacks =
object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(
activity: Activity,
savedInstanceState: Bundle?
) {
for (watcher in fragmentDestroyWatchers) {
watcher(activity)
}
}
}

override fun install() {
application.registerActivityLifecycleCallbacks(lifecycleCallbacks)
}
复制代码

ActivityWatcher 同样的,install是注册了生命周期监听。不过是在对每个 activity create 的时候,交给 fragmentDestroyWatchers 元素们监听。所以 fragmentDestroyWatchers才是真正的fragmentviewmodel 监听者。 接下来看 fragmentDestroyWatchers 的元素们创建:

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

//(1.3.1) android框架自带的fragment泄漏监测支持从 AndroidO(26)开始。
if (SDK_INT >= O) {
fragmentDestroyWatchers.add(
AndroidOFragmentDestroyWatcher(reachabilityWatcher)
)
}
//(1.3.2)
getWatcherIfAvailable(
ANDROIDX_FRAGMENT_CLASS_NAME,
ANDROIDX_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
//(1.3.3)
getWatcherIfAvailable(
ANDROID_SUPPORT_FRAGMENT_CLASS_NAME,
ANDROID_SUPPORT_FRAGMENT_DESTROY_WATCHER_CLASS_NAME,
reachabilityWatcher
)?.let {
fragmentDestroyWatchers.add(it)
}
fragmentDestroyWatchers
}
复制代码

可以看到内部创建了AndroidOFragmentDestroyWatcher 来针对Fragment 进行监听。原理是利用在 FragmentManager 中注册 FragmentManager.FragmentLifecycleCallbacks 来监听fragment 和 fragment.view 以及viewmodel 的实例泄漏。 从官方文档可知,android内部的 fragment 在Api 26中才添加。所以LeakCanary针对于android框架自带的fragment泄漏监测支持也是从 AndroidO(26)开始,见代码(1.3.1)。 标注的 1.3.1,1.3.2,1.3.3 实例化的三个Wathcer 分别是 AndroidOFragmentDestroyWatcher,AndroidXFragmentDestroyWatcher,AndroidSupportFragmentDestroyWatcher。内部实现代码大同小异,通过反射实例化不同的Watcher实现了androidX 和support 以及安卓版本间的兼容。

(1.3.1) AndroidOFragmentDestroyWatcher 实例

(1.3.1)处的代码添加了一个androidO的观察者实例。详情见代码,因为实现大同小异,分析参考1.3.2.

(1.3.2) AndroidXFragmentDestroyWatcher 实例

(1.3.2)处的代码 调用 getWatcherIfAvailable 通过反射创建了AndroidXFragmentDestroyWatcher实例,如果不存在Androidx库则返回null。 现在跳到 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?
) {
//(1.3.2.1)初始化 ViewModelClearedWatcher
ViewModelClearedWatcher.install(fragment, reachabilityWatcher)
}

override fun onFragmentViewDestroyed(
fm: FragmentManager,
fragment: Fragment
) {
//监测 fragment.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
) {
//监测 fragment 的泄漏情况
reachabilityWatcher.expectWeaklyReachable(
fragment, "${fragment::class.java.name} received Fragment#onDestroy() callback"
)
}
}

///初始化,注册fragmentLifecycleCallbacks
override fun invoke(activity: Activity) {
if (activity is FragmentActivity) {
val supportFragmentManager = activity.supportFragmentManager
supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, true)
//注册activity的 viewModel 监听回调
ViewModelClearedWatcher.install(activity, reachabilityWatcher)
}
}
}
复制代码

通过源码可以看到,初始化该watcher是通过以下几步。

  1. FragmentManager.registerFragmentLifecycleCallbacks 注册监听回调
  2. ViewModelClearedWatcher.install 初始化了对于activity.viewModel的监听
  3. 在回调onFragmentCreated 中回调中使用ViewModelClearedWatcher.install注册了对于fragment.viewModel的监听。
  4. 在 onFragmentViewDestroyed 监听 fragment.view 的泄漏
  5. 在 onFragmentDestroyed 监听 fragment的泄漏。 监听方法和ActivityWatcher大同小异,不同是多了个 ViewModelClearedWatcher.install 。现在分析这一块的源码,也就是标注中的 (1.3.2.1)。
//该watcher 继承了ViewModel,生命周期被 ViewModelStoreOwner 管理。
internal class ViewModelClearedWatcher(
storeOwner: ViewModelStoreOwner,
private val reachabilityWatcher: ReachabilityWatcher
) : ViewModel() {

private val viewModelMap: Map<String, ViewModel>?

init {
//(1.3.2.3)通过反射获取所有的 store 存储的所有viewModelMap
viewModelMap = try {
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() {
///(1.3.2.4) viewmodle 被清理释放的时候回调,检查所有viewmodle 是否会有泄漏
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")
override fun <T : ViewModel?> create(modelClass: Class<T>): T =
ViewModelClearedWatcher(storeOwner, reachabilityWatcher) as T
})
///(1.3.2.2) 获取ViewModelClearedWatcher实例
provider.get(ViewModelClearedWatcher::class.java)
}
}
}
复制代码

通过代码,可以看到viewModel的泄漏监测是通过创建一个新的viewModel实例来实现。在该实例的onCleared处监听storeOwner的其余 viewModel 是否有泄漏。标注出的代码逐一分析:

(1.3.2.2 ) 处代码:

获取ViewModelClearedWatcher 实例,在自定义的 Factory中传入storeOwner 和 reachabilityWatcher。

(1.3.2.3 ) 处代码:

通过反射获取storeOwner 的viewModelMap

(1.3.2.4 ) 处代码:

在ViewModel完成使命OnClear的时候,开始监测storeOwner旗下所有ViewModel的内存泄漏情况。

(1.3-end)Fragment 和 viewmodel 监测泄漏总结:

监测方式都是通过ObjectWatcher的 expectWeaklyReachable 方法进行。fragment 利用FragmentLifecyclerCallback回调注册实现,ViewModel 则是在对应StoreOwner下创建了监测viewModel来实现生命周期的响应。 其中我们也能学习到通过反射来创建对应的平台兼容实现对象方式。以及借助创建viewModel来监听其余ViewModel生命周期的想法。

(1.4) RootViewWatcher 的源码分析

默认的四个Watcher中,来到了接下来的 RootViewWatcher。window rootview 监听依赖了squre自家的Curtains框架。

implementation "com.squareup.curtains:curtains:1.0.1"
复制代码

类的关键源码如下:

 private val listener = OnRootViewAddedListener { rootView ->
//如果是 Dialog TOOLTIP, TOAST, UNKNOWN 等类型的windows
//trackDetached 为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)
}
})
}
}

override fun install() {
Curtains.onRootViewsChangedListeners += listener
}

override fun uninstall() {
Curtains.onRootViewsChangedListeners -= listener
}
}
复制代码

看到关键代码,就是 在Curtains中添加onRootViewsChangedListeners 监听器。当windowsType类型为 **Dialog** ***TOOLTIP***, ***TOAST*****,**或者未知的时候 ,在 onViewDetachedFromWindow 的时候监听泄漏情况。 Curtains中的监听器会在windows rootView 变化的时候被全局调用。Curtains是squareup 的另一个开源库,Curtains 提供了用于处理 Android 窗口的集中式 API。具体移步他的官方仓库

(1.5) ServiceWatcher 监听Service内存泄漏

接下来就是AppWatcher中的最后一个Watcher。 ServiceWatcher。代码比较长,截取关键点分析。

(1.5.1)先看成员变量 activityThreadServices :

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>
}
复制代码

activityThreadServices 是个装了所有<IBinder, Service> 对的Map。代码中可以看到很粗暴地,直接通过反射从ActivityThread实例中拿到了mServices 变量 。赋值给activityThreadServices。 源码中有多个swap操作,在install的时候执行,主要目的是将原来的一些service相关生命周期回调加上一些钩子,用来监测内存泄漏,并且会在unInstall的时候给换回来。

(1.5.2)swapActivityThreadHandlerCallback :

拿到ActivityThread 的Handler,将其回调的 handleMessage,换成加了料的Handler.Callback,加料代码如下

Handler.Callback { msg ->
if (msg.what == STOP_SERVICE) {
val key = msg.obj as IBinder
activityThreadServices[key]?.let {
onServicePreDestroy(key, it)
}
}
mCallback?.handleMessage(msg) ?: false
}
复制代码

代码中可以看到,主要是对于 STOP_SERVICE 的操作做了一个钩子,在之前执行 onServicePreDestroy。主要作用是为该service 创建一个弱引用,并且加到servicesToBeDestroyed[token] 中 。

(1.5.3)然后再看 swapActivityManager 方法。

该方法完成了将ActivityManager替换成IActivityManager的一个动态代理类。代码如下:

Proxy.newProxyInstance(
activityManagerInterface.classLoader, arrayOf(activityManagerInterface)
) { _, method, args ->
//private const val METHOD_SERVICE_DONE_EXECUTING = "serviceDoneExecuting"
if (METHOD_SERVICE_DONE_EXECUTING == method.name) {
val token = args!![0] as IBinder
if (servicesToBeDestroyed.containsKey(token)) {
///(1.5.3)
onServiceDestroyed(token)
}
}
try {
if (args == null) {
method.invoke(activityManagerInstance)
} else {
method.invoke(activityManagerInstance, *args)
}
} catch (invocationException: InvocationTargetException) {
throw invocationException.targetException
}
}
复制代码

代码所示,替换后的ActivityManager 在调用serviceDoneExecuting 方法的时候添加了个钩子,如果该service在之前加入的servicesToBeDestroyed map中,则调用onServiceDestroyed 监测该service内存泄漏。

(1.5.4)代码的onServiceDestroyed具体代码如下

private fun onServiceDestroyed(token: IBinder) {
servicesToBeDestroyed.remove(token)?.also { serviceWeakReference ->
serviceWeakReference.get()?.let { service ->
reachabilityWatcher.expectWeaklyReachable(
service, "${service::class.java.name} received Service#onDestroy() callback"
)
}
}
}
复制代码

这里面的代码很熟悉,和之前监测activity等是一样的。 回到swapActivityManager方法,看代理ActivityManager的具体类型。 可以看到代理的对象如下面代码所示,根据版本不同可能是ActivityManager 实例或者是ActivityManagerNative实例。 代理的接口是 Class.forName("android.app.IActivityManager")

val (className, fieldName) = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
"android.app.ActivityManager" to "IActivityManagerSingleton"
} else {
"android.app.ActivityManagerNative" to "gDefault"
}
复制代码

(1.5-end)Service 泄漏监测总结

总结一下,service的泄漏分析通过加钩子的方式,对一些系统执行做了监听。主要分为以下几步:

  1. 获取ActivityThread中mService变量,得到service实例的引用
  2. 通过swapActivityThreadHandlerCallback 在ActivityThread 的 Handler.sendMessage 中添加钩子,在执行到msg.what == STOP_SERVICE 的时候


0 个评论

要回复文章请先登录注册