首先从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中的一个接口<ActivityLifecycleCallbacks>,同时Application中维护了一个ArrayList<ActivityLifecycleCallbacks>
@UnsupportedAppUsage
private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
new ArrayList<ActivityLifecycleCallbacks>();
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<InstallableWatcher> = 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<InstallableWatcher> = appDefaultWatchers(application)
四大金刚正式登场
fun appDefaultWatchers(
application: Application,
reachabilityWatcher: ReachabilityWatcher = objectWatcher
): List<InstallableWatcher> {
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<Activity>的集合
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 <T : ViewModel?> create(modelClass: Class<T>): 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<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>
}
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,
/**
* Calls to [watch] will be ignored when [isEnabled] returns false
*/
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<EventListener> = 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,
/**
* An exception wrapping the actual exception that was thrown.
*/
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模式.
才疏学浅,欢迎探讨.