Análisis del principio del código fuente de la última versión 2.8.1 de LeakCanary [versión de kotlin a principios de 2022]

Primero, hablemos sobre el uso de LeakCanary y luego vayamos a la capa inferior para analizar la lógica del código fuente.

Cómo usar la nueva versión de kotlin

dependencies {
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
}

Solo un paso y listo.

Qué fugas se monitorean por defecto

Según el sitio web oficial, no hay una dependencia intrusiva y el monitoreo de pérdida de memoria de los siguientes módulos se inyectará automáticamente

LeakCanary detecta automáticamente fugas de los siguientes objetos:

destruido Instancias de actividad
destruidas Fragmento instancias
destruido fragmento Ver instancias
borradas ViewModel instancias

flujo de trabajo general

Pasará por los siguientes 4 pasos para hacer todo el trabajo.

  • Detección de objetos retenidos Seguimiento de objetos retenidos que no han sido reciclados
  • Volcar el montón.
  • Analizando el montón Analizando el montón
  • Categorización de fugas. Las fugas de montón se dividen en

Supervisar objetos no recogidos

Cuando esté visible en primer plano, comenzará a volcar cuando detecte que hay 5 objetos sin reciclar

Cuando no está visible en segundo plano, comenzará a volcar cuando detecte que hay algún objeto que no ha sido reciclado.

Se monitorea cada 2 segundos y el ciclo de volcado es cada 5 segundos.

montón de volcado

Cuando se alcance el umbral anterior, se activará el volcado y
se generará el archivo .hprof

Analizar montón

Ahora lo analiza Shark

Clasificación de fugas

##############################

Ingrese al tema y rompa el código fuente.

Algunos proveedores y actividades se inyectarán automáticamente en el archivo compilado.

1: ProcessLifecycleOwnerInitializer

androidx.lifecycle.ProcessLifecycleOwnerInitializer

Este es un ContentProvider que viene con Android

En el método onCreate, se realizan principalmente dos operaciones

LifecycleDispatcher.init(getContext());
ProcessLifecycleOwner.init(getContext());

1.1: LifecycleDispatcher

//底层会在application中把这个callback纳入application的维护范畴内
((Application) context.getApplicationContext())
                .registerActivityLifecycleCallbacks(new DispatcherActivityCallback());

Prestar atención a DispatcherActivityCallback en realidad hizo una cosa

    @VisibleForTesting
    static class DispatcherActivityCallback extends EmptyActivityLifecycleCallbacks {

        @Override
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
           //核心就是这句了.
            ReportFragment.injectIfNeededIn(activity);
        }
..........省略.......................
    }

La devolución de llamada anterior es una interfaz en la aplicación, y se mantiene una ArrayList en la aplicación

 @UnsupportedAppUsage
    private ArrayList<ActivityLifecycleCallbacks> mActivityLifecycleCallbacks =
            new ArrayList<ActivityLifecycleCallbacks>();

1.2: propietario del ciclo de vida del proceso

  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);
                }
            }
          .......省略.......
        });
    }

**Resumen: Las dos devoluciones de llamada de registro del ciclo de vida anteriores se procesan en última instancia en la clase Aplicación.

public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.add(callback);
        }
    }

    public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        synchronized (mActivityLifecycleCallbacks) {
            mActivityLifecycleCallbacks.remove(callback);
        }
    }

2: FugaCanaryFileProvider

leakcanary.internal.LeakCanaryFileProvider

No entendí esta clase, pero probablemente significa que se usa cuando se opera la clase de archivo.

3: MainProcessAppWatcherInstaller

leakcanary.internal.MainProcessAppWatcherInstaller

Esta clase también está integrada con ContentProvider, que reemplaza la instalación manual de la versión anterior de LeackCanary.En el método onCreate de esta clase, se realizarán automáticamente las siguientes operaciones [Miraculous Pen]

 override fun onCreate(): Boolean {
    val application = context!!.applicationContext as Application
    AppWatcher.manualInstall(application)
    return true
  }

3.1: Código central

 @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: Carga reflexiva de 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
    }
  }

El parámetro pasado anteriormente como aplicación se ejecutará en el método de invocación

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()
            )
          }
        }
      }
    }

En resumen: a través del mecanismo único de ContentProvider en Android, la operación de instalación se activa automáticamente y, en la operación de instalación, se ejecuta a través del reflejo de la clase.

  • Compruebe si solo está habilitado el modo de depuración
  • Crea un objeto Watcher y escucha
  • Crear un colector de GC
  • Crear un subproceso asíncrono de fondo
  • Supervise si la aplicación es visible o no, y llame a diferentes estrategias de umbral para volcar el montón
  • Crear un icono de acceso directo en el escritorio

3.3: Inyección automática de diferentes oyentes

En el registro de AppWatcher, las últimas 3 líneas tienen acciones muy críticas, como sigue

watchersToInstall.forEach {
      it.install()
    }
watchersToInstall: List<InstallableWatcher> = appDefaultWatchers(application)

Los Cuatro King Kong debutan oficialmente

  fun appDefaultWatchers(
    application: Application,
    reachabilityWatcher: ReachabilityWatcher = objectWatcher
  ): List<InstallableWatcher> {
    return listOf(
      ActivityWatcher(application, reachabilityWatcher),
      FragmentAndViewModelWatcher(application, reachabilityWatcher),
      RootViewWatcher(reachabilityWatcher),
      ServiceWatcher(reachabilityWatcher)
    )
  }

Muchos amigos informaron que la versión anterior de LeakCanary tiene funciones limitadas, solo monitorea Actividad y Fragmento, y no puede monitorear Servicio. Esta vez está arreglado.

3.3.1: Monitor de actividad

Heredar la interfaz InstallableWatcher tiene solo dos métodos, instalar y desinstalar, declarando una variable global para realizar las siguientes operaciones

 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

La capa inferior aquí en realidad depende de la Actividad, y también está subdividida y es compatible con el siguiente
Android8.0 y superior

Fragmento de la serie Android x

Serie de soporte de Android de fragmentos

//定义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
  }

Uso de 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 es diferente al anterior

Está escrito de la misma manera que AndroidOFragmentDestroyWatcher, lo único es que el paquete de fragmentos importado es diferente y hay dos métodos más reescritos para el procesamiento.

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)
    }
  }

A través de ViewModel en Androidx

  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

Igual que AndroidOFragmentDestroyWatcher, lo único es que el paquete Fragment al que se hace referencia es diferente

import android.support.v4.app.Fragment
import android.support.v4.app.FragmentActivity
import android.support.v4.app.FragmentManager

En resumen, cuando se procesa fragmentWatcher, se maneja distinguiendo la compatibilidad y, finalmente, a través de fragmentManager en la actividad de la que depende el fragmento para la gestión del ciclo de vida.

3.3.3: RootViewWatcher

Principalmente relacionado con la Vista, la premisa es que la Vista no está adjunta a la Actividad/ventana emergente, y si la configuración en el proyecto admite ventanas emergentes

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: Observador de servicios

asociación de referencia débil

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

creación de reflexión

 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>
  }

El código fuente central del servicio no se ha entendido por el momento, y probablemente se sepa que hay una reflexión llamando a IActivityManager

Pegue el código fuente central en el método de instalación

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" }
    }

En resumen, sabemos por qué la nueva versión de leakCanary solo necesita depender de él, porque lo anterior se procesa automáticamente.

4: luego analice el área del montón de volcado

Mantenemos una clase ObjectWatcher en la clase AppWatcher

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: En la clase AppWatcher de la siguiente manera

  @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 }

El controlador mencionado anteriormente es el controlador del hilo principal

internal val mainHandler by lazy { Handler(Looper.getMainLooper()) }

En el método de ejecución de invocación de InternalLeakCanary, hay una operación para enviar una notificación al monitorear

5: Receptor de notificaciones

Esta clase es principalmente responsable de la operación de recibir el evento de transmisión DUMP_HEAP,

5.1: En el paso 3.3 anterior, puede ver el procesamiento de envío de transmisión

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 En la clase HenapDumpControl

fun iCanHasHeap(): ICanHazHeap {
    ........省略代码.........

    synchronized(this) {
      if (::latest.isInitialized && dumpHeap is Yup && latest is Nope) {
        //dump的调度处理
        InternalLeakCanary.scheduleRetainedObjectCheck()
      }
      latest = dumpHeap
    }

    return dumpHeap
  }

5.3: En INternalLeakCanary

  fun scheduleRetainedObjectCheck() {
    if (this::heapDumpTrigger.isInitialized) {
      heapDumpTrigger.scheduleRetainedObjectCheck()
    }
  }

5.4 En 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 Procesamiento de recepción en transmisión

 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: Procesamiento de recepción de volcados en la clase InternalLeakCanary

 fun onDumpHeapReceived(forceDump: Boolean) {
    if (this::heapDumpTrigger.isInitialized) {
      heapDumpTrigger.onDumpHeapReceived(forceDump)
    }
  }

##5.8 Procesamiento en 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 Procesamiento 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 Recopilación de eventos en la clase 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)
    }

Finalmente, se llaman varias clases de datos HeapAnalysisFailure HeapAnalysisSuccess en HeapAnalysis, y el método toString() dentro es el registro de error empalmado que vimos en LeakCanary.

Código de la sección de resumen

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

Similar a 5.10.1 con menos pasos

  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)
      }
    }
  }

Arriba: el volcado y el análisis de monitoreo de dependencia de LeakCanary se aclaran básicamente.

6 FontaneroInstalador

leakcanary.internal.PlomberInstaller

Además, agregue alimentos para complementar esto. La función de esta clase es principalmente reflejar si las diferentes versiones y los diferentes fabricantes de teléfonos móviles admiten algunas API.

Principalmente para diferentes modelos y diferentes versiones, algunos escenarios especiales causarán fugas, que se establecerán manualmente en nulo cuando la actividad se destruya para facilitar el reciclaje.

AndroidLeakFixes.applyFixes(application)

Este análisis se realiza en segundo plano por un solo grupo de subprocesos

 Executors.newSingleThreadScheduledExecutor

Por ejemplo, por ejemplo, hay una versión para dispositivos Samsung que no está entre 19 y 21
Reflejando el campo mLastHoveredView en TextView

  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" }
          }
        }
      }
    }
  },

Actividad de fuga

actividad.interna.de.leakcanary.LeakActivity

Abrimos el icono canario para mostrar esta Actividad.

Importar el archivo .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

Se utiliza principalmente para solicitar un permiso.

  • Desde la perspectiva del modo de diseño, se utiliza el modo de fábrica (Wacher y analizador)
  • Utilice inteligentemente la función ContentProvider para lograr un acceso de código de una línea no intrusivo
  • En comparación con la versión anterior, se ha agregado el monitoreo de RootView y Service

Nota: Este anuncio oficial solo se puede realizar en modo de depuración.

Lo anterior es el análisis general.

Supongo que te gusta

Origin blog.csdn.net/admin_jalen/article/details/122640736
Recomendado
Clasificación