Skip to content

bytebeats/Anr-Monitor

Repository files navigation

Anr-Monitor

Android Performance Tools. ANR, Dead locks and lags.


Android性能监控工具. 包括了对 ANR 信息的收集, 死锁时线程信息的收集以及卡顿的监测.

ANR信息收集原理


通过在后台开启一条线程, 只要没有被打断, 就一直在循环监测.
每一次循环开始的时候, 向Handler(Looper.getMainLooper())发送一条消息, 用于取消收集 ANR 的开始的标签.
然后子线程休息指定时间(可以自由设置).
如果此时主线程卡顿了指定时间, 那么子线程从休眠中唤醒, 此时收集 ANR 的标签没有取消, 则开始收集线程(全部线程或者主线程或者特定类型的线程)的堆栈信息, 通过回调接收.

卡顿的监测原理


通过 Choreographer#postFrameCallback 或者 Looper.gerMainLooper().setPrinter 方式,
传入自己的 FrameCallback 或者 Printer. <br>通过对doFrame(frameTimeNanos)/println(message)计算每一次doFrame/println的时间间隔, <br>计算丢帧或者Looper中每一个Message` 执行的耗时
从而判断应用的卡顿情况.

死锁时线程信息的收集原理


主要是在发生死锁时, 通过 Android 系统底层函数 Monitor#GetLockOwnerThreadId 或者锁此时的持有者线程(通过反射该线程的 nativePeer 从当前线程查找)
通过 Thread#enumerate(Thread[]) 获取全部线程, 并利用算法查找此时竞争同一把锁的线程竞争闭环, 从而找出死锁的信息.
因为需要 Hook 底层 Monitor#GetLockOwnerThreadId 函数, 所以使用了 JNINDK 技术.

How to use?


使用指定地址的 MavenCentral:
在根build.gradle文件中, 添加:

    repositories {
       maven { url('https://repo1.maven.org/maven2/') }
               ...
    }


在 module build.gradle 文件中, 添加:

    //load from maven central
    implementation('io.github.bytebeats:anr:1.0.0')
    implementation('io.github.bytebeats:lags:1.0.1')
    implementation('io.github.bytebeats:deadlock:1.0.0')


在自定义的 Application 中:

    class APMApplication : Application() {
       val anrMonitor = AnrMonitor(3000)
       val anrMonitor = AnrMonitor2(3000)

       val silentAnrListener = object : AnrListener {
           override fun onAppNotResponding(error: AnrError) {
               Log.d("anr-log", "onAppNotResponding", error)
           }
       }

       var duration = 4L

       override fun onCreate() {
           super.onCreate()
           AnrLog.logStackTrace = false
           anrMonitor.setIgnoreDebugger(true)
               .setReportAllThreads()
               .setAnrListener(object : AnrListener {
                   override fun onAppNotResponding(error: AnrError) {
                       AnrLog.logd("onAppNotResponding")
                       AnrLog.logd(error)
                       try {
                           ObjectOutputStream(ByteArrayOutputStream()).writeObject(error)
                       } catch (e: IOException) {
                           throw RuntimeException(e)
                       }
                       AnrLog.logd("Anr Error was successfully serialized")
                       throw error
                   }
               }).setAnrInterceptor(object : AnrInterceptor {
                   override fun intercept(duration: Long): Long {
                       val ret = [email protected] - duration
                       if (ret > 0) {
                           AnrLog.logd(
                               "Intercepted ANR that is too short ($duration ms), postponing for $ret ms."
                           )
                       }
                       return ret
                   }
               })
               .setOnInterruptedListener(object : OnInterruptedListener {
                   override fun onInterrupted(e: InterruptedException) {
                       throw e
                   }
               })
           ProcessLifecycleOwner.get().lifecycle.addObserver(anrMonitor)

           val lagMonitor = LagMonitor.Builder(this.applicationContext)
               .setThresholdTimeMillis(3000L)
               .setLagLogEnabled(true)
               .setMonitorMode(LagMonitor.MonitorMode.UI)
               .setOnFrameJankListener(object : OnFrameJankListener {
                   override fun onJank(janks: Int) {
                       Log.d("lag-log", "janks: $janks")
                   }
               })
               .setOnUIThreadRunListener(object : OnUIThreadBlockListener {
                   override fun onBlock(lagTime: Long, uiRunTime: Long) {
                       Log.d("lag-log", "lagTime: $lagTime,  uiRunTime: $uiRunTime")
                   }
               })
               .setOnProcessNotRespondingListener(object : OnProcessNotRespondingListener {
                   override fun onNotResponding(processInfo: String?) {
                       Log.d("lag-log", "processInfo: $processInfo")
                   }
               })
               .build()
           ProcessLifecycleOwner.get().lifecycle.addObserver(lagMonitor)
       }

       override fun onTerminate() {
           super.onTerminate()
           anrMonitor.onAppTerminate()
       }
   }

Stargazers over time

Stargazers over time

MIT License

Copyright (c) 2021 Chen Pan

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

About

Android Performance Tools. ANR, Dead locks and lags. Android性能监测工具. 监测了 ANR, 死锁和卡顿.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published