1. 系统的性能
Watchdog机制
Android SWT : Android Software Watchdog Timeout
作用:监控核心服务和核心线程是否卡住,如果判断阻塞 60s ,就会把系统重启,来保证系统恢复正常状态.
-
Monitor Checker,用于检查是Monitor对象可能发生的死锁, AMS, PKMS, WMS等核心的系统服务都是Monitor对象。预警我们不能长时间持有核心系统服务的对象锁,否则会阻塞很多函数的运行 -
Looper Checker,用于检查线程的消息队列是否长时间处于工作状态。Watchdog自身的消息队列,Ui, Io, Display这些全局的消息队列都是被检查的对象。此外,一些重要的线程的消息队列,也会加入到Looper Checker中,譬如AMS, PKMS,这些是在对应的对象初始化时加入的。???????预警我们不能长时间的霸占消息队列,否则其他消息将得不到处理。这两类都会导致系统卡住(System Not Responding)。 -
对于Looper Checker而言,会判断线程的消息队列是否处于空闲状态。 如果被监测的消息队列一直闲不下来,则说明可能已经阻塞等待了很长时间 -
对于Monitor Checker而言,会调用实现类的monitor方法,譬如上文中提到的AMS.monitor()方法, 方法实现一般很简单,就是获取当前类的对象锁,如果当前对象锁已经被持有,则monitor()会一直处于wait状态,直到超时,这种情况下,很可能是线程发生了死锁
? ? ? ?只要Watchdog没有发现超时的任务,HandlerChecker就会被不停的调度
-
watchdog的初始化: final Watchdog watchdog = Watchdog.getInstance();
watchdog.start(); watchdog的添加:
public final class ActivityManagerService extends ActivityManagerNative
implements Watchdog.Monitor
public void monitor() {
synchronized (this) { }
}
watchdog的的检测机制: - Watchdog运行后,便开始无限循环,依次调用每一个HandlerChecker的scheduleCheckLocked()方法
- 调度完HandlerChecker之后,便开始定期检查是否超时,每一次检查的间隔时间由CHECK_INTERVAL常量设定,为30秒
- 每一次检查都会调用evaluateCheckerCompletionLocked()方法来评估一下HandlerChecker的完成状态:?
- COMPLETED表示已经完成
- WAITING和WAITED_HALF表示还在等待,但未超时
- OVERDUE表示已经超时。默认情况下,timeout是1分钟,但监测对象可以通过传参自行设定,譬如PKMS的Handler Checker的超时是10分钟
- 如果超时时间到了,还有HandlerChecker处于未完成的状态(OVERDUE),则通过getBlockedCheckersLocked()方法,获取阻塞的HandlerChecker,生成一些描述信息
- 保存日志,包括一些运行时的堆栈信息,这些日志是我们解决Watchdog问题的重要依据。如果判断需要杀掉system_server进程,则给当前进程(system_server)发送signal 9
日志
????????adb shell logcat?-b all?
- event?通过android.util.EventLog工具类打印的日志,一些重要的系统事件会使用此类日志
- main?通过android.util.Log工具类打印的日志,应用程序,尤其是基于SDK的应用程序,会使用此类日志
- system?通过android.util.Slog工具类打印的日志,系统相关的日志一般都是使用此类日志,譬如SystemServer
- radio?通过android.util.Rlog工具类打印的日志,通信模块相关的日志一般都是使用此类日志,譬如RIL
????????binder日志:adb shell cat ?/proc/binder
- failed_transaction_log
- transaction_log
- transactions
- stats
案例1:搜索watchdog发生
watchdog: Blocked in handler XXX # 表示HandlerChecker超时了
watchdog: Blocked in monitor XXX # 表示MonitorChecker超时了
******************************************************************
watchdog杀死系统的日志:
???????Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: XXX Watchdog: XXX Watchdog: "*** GOODBYE!
********************************************************************
1.检索到下面信息
W Watchdog: *** WATCHDOG KILLING SYSTEM PROCESS: Blocked in monitor com.android.server.wm.WindowManagerService on foreground thread (android.fg)
2.打开system_server进程的traces,检索?android.fg?可以快速定位到该线程的函数调用栈:
-
"android.fg" prio=5 tid=25 Blocked -
| group="main" sCount=1 dsCount=0 obj=0x12eef900 self=0x7f7a8b1000 -
| sysTid=973 nice=0 cgrp=default sched=0/0 handle=0x7f644e9000 -
| state=S schedstat=( 3181688530 2206454929 8991 ) utm=251 stm=67 core=1 HZ=100 -
| stack=0x7f643e7000-0x7f643e9000 stackSize=1036KB -
| held mutexes= -
at com.android.server.wm.WindowManagerService.monitor(WindowManagerService.java:13125) -
- waiting to lock <0x126dccb8> (a java.util.HashMap) held by thread 91 -
at com.android.server.Watchdog$HandlerChecker.run(Watchdog.java:204) -
at android.os.Handler.handleCallback(Handler.java:815) -
at android.os.Handler.dispatchMessage(Handler.java:104) -
at android.os.Looper.loop(Looper.java:194) -
at android.os.HandlerThread.run(HandlerThread.java:61) -
at com.android.server.ServiceThread.run(ServiceThread.java:46)
3.由上知道了91进程阻塞,检索?tid=91
-
"Binder_C" prio=5 tid=91 Native -
| group="main" sCount=1 dsCount=0 obj=0x12e540a0 self=0x7f63289000 -
| sysTid=1736 nice=0 cgrp=default sched=0/0 handle=0x7f6127c000 -
| state=S schedstat=( 96931835222 49673449591 260122 ) utm=7046 stm=2647 core=2 HZ=100 -
| stack=0x7f5ffbc000-0x7f5ffbe000 stackSize=1008KB -
| held mutexes= -
at libcore.io.Posix.writeBytes(Native method) -
at libcore.io.Posix.write(Posix.java:258) -
at libcore.io.BlockGuardOs.write(BlockGuardOs.java:313) -
at libcore.io.IoBridge.write(IoBridge.java:537) -
at java.io.FileOutputStream.write(FileOutputStream.java:186) -
at com.android.internal.util.FastPrintWriter.flushBytesLocked(FastPrintWriter.java:334) -
at com.android.internal.util.FastPrintWriter.flushLocked(FastPrintWriter.java:355) -
at com.android.internal.util.FastPrintWriter.appendLocked(FastPrintWriter.java:303) -
at com.android.internal.util.FastPrintWriter.print(FastPrintWriter.java:466) -
- locked <@addr=0x134c4910> (a com.android.internal.util.FastPrintWriter$DummyWriter) -
at com.android.server.wm.WindowState.dump(WindowState.java:1510) -
at com.android.server.wm.WindowManagerService.dumpWindowsNoHeaderLocked(WindowManagerService.java:12279) -
at com.android.server.wm.WindowManagerService.dumpWindowsLocked(WindowManagerService.java:12266) -
at com.android.server.wm.WindowManagerService.dump(WindowManagerService.java:12654) -
- locked <0x126dccb8> (a java.util.HashMap) -
at android.os.Binder.dump(Binder.java:324) -
at android.os.Binder.onTransact(Binder.java:290)
4.解决方法:在这个IO写操作上加一个超时机制,并且这个超时小于Watchdog的超时,不就可以让线程释放它所占有的锁了吗
案例2:
1.检索到
2.分析出红色的是时间点和进程号,找到trace.txt
3.搜索ActivityManager
-
"ActivityManager" prio=5 tid=17 TimedWaiting -
| group="main" sCount=1 dsCount=0 obj=0x12c0e6d0 self=0x7f84caf000 -
| sysTid=938 nice=-2 cgrp=default sched=0/0 handle=0x7f7d887000 -
| state=S schedstat=( 107864628645 628257779012 60356 ) utm=7799 stm=2987 core=2 HZ=100 -
| stack=0x7f6e68f000-0x7f6e691000 stackSize=1036KB -
| held mutexes= -
at java.lang.Object.wait!(Native method) -
- waiting on <0x264ff09d> (a com.android.server.am.ActivityManagerService$5) -
at java.lang.Object.wait(Object.java:422) -
at com.android.server.am.ActivityManagerService.dumpStackTraces(ActivityManagerService.java:5395) -
at com.android.server.am.ActivityManagerService.dumpStackTraces(ActivityManagerService.java:5282) -
at com.android.server.am.ActivityManagerService$AnrActivityManagerService.dumpStackTraces(ActivityManagerService.java:22676) -
at com.mediatek.anrmanager.ANRManager$AnrDumpMgr.dumpAnrDebugInfoLocked(SourceFile:1023) -
at com.mediatek.anrmanager.ANRManager$AnrDumpMgr.dumpAnrDebugInfo(SourceFile:881) -
at com.android.server.am.ActivityManagerService.appNotResponding(ActivityManagerService.java:6122) -
- locked <0x21c77912> (a com.mediatek.anrmanager.ANRManager$AnrDumpRecord) -
at com.android.server.am.BroadcastQueue$AppNotResponding.run(BroadcastQueue.java:228) -
at android.os.Handler.handleCallback(Handler.java:815) -
at android.os.Handler.dispatchMessage(Handler.java:104) -
at android.os.Looper.loop(Looper.java:192) -
at android.os.HandlerThread.run(HandlerThread.java:61) -
at com.android.server.ServiceThread.run(ServiceThread.java:46)
4.分析得知AMS设计了一个200毫秒的超时锁。
5.在sys_log中检索”ANR in”关键字或在event_log中检索”anr”关键字
-
10-14 17:10:04.215 892 938 E ANRManager: ANR in com.android.systemui, time=27097912 -
10-14 17:10:04.215 892 938 E ANRManager: Reason: Broadcast of Intent { act=android.intent.action.TIME_TICK flg=0x50000114 (has extras) } -
10-14 17:10:04.215 892 938 E ANRManager: Load: 89.22 / 288.15 / 201.91 -
10-14 17:10:04.215 892 938 E ANRManager: Android time :[2015-10-14 17:10:04.14] [27280.396] -
10-14 17:10:04.215 892 938 E ANRManager: CPU usage from 17016ms to 0ms ago: -
10-14 17:10:04.215 892 938 E ANRManager: 358% 23682/float_bessel: 358% user + 0% kernel -
10-14 17:10:04.215 892 938 E ANRManager: 57% 23604/debuggerd64: 3.8% user + 53% kernel / faults: 11369 minor -
10-14 17:10:04.215 892 938 E ANRManager: 2% 892/system_server: 0.9% user + 1% kernel / faults: 136 minor
2.应用的性能问题
ANR
ANR弹出对话框提示用户
InputDispatching Timeout:5秒内无法响应屏幕触摸事件或键盘输入事件 BroadcastQueue Timeout :在执行前台广播(BroadcastReceiver)的onReceive()函数时10秒没有处理完成,后台为60秒
ContentProvider Timeout :ContentProvider的publish在10s内没进行完 Service Timeout :前台服务20秒内,后台服务在200秒内没有执行完毕
注意:耗时操作本身是不会产生ANR的,导致ANR的根本还是应用程序无法在一定时间内响应用户的操作。
ANR原因
如何避免ANR
Handler机制:
Looper.loop 为什么不会导致死锁?
1.如果不用Looper.loop的话应用也就退出了,代码其实就是在这个循环里面去执行的,固然不会阻塞了
2.主线程大多数时候都是处于休眠状态,并不会消耗大量CPU资源
3.若是某个消息处理时间过长,好比你在onCreate(),onResume()里面处理耗时操做,那么下一次的消息好比用户的点击事件不能处理了,整个循环就会产生卡顿,时间一长就成了ANR
总结:Looer.loop()方法可能会引发主线程的阻塞,但只要它的消息循环没有被阻塞,能一直处理事件就不会产生ANR异常。??????????????
|