anrdisplay cpu usagee是所有进程吗

【腾讯bugly干货分享】精神哥手把手教你如何智斗ANR
时间: 10:11:23
&&&& 阅读:2008
&&&& 评论:
&&&& 收藏:0
标签:&&&&&&
上帝说要有ANR,于是Bugly就有了ANR上报,那么ANR到底是什么?
最近很多童鞋问起精神哥ANR的问题,那么这次就来聊一下,鸡爪怎么泡才好吃,噢不,是如何快速定位ANR。
简单说,通常就是App运行的时候,duang~卡住了,怎么搞都动不了。当卡住超过一定时间,Android系统认为这就是一次“ANR(Application Not Responding)”。
具体说,在以下情况发生时,会发生ANR(可能在不同ROM 中时间有所更改):
用户的输入在5s内没被App响应;
BroadcastReceiver的onReceiver()超过10s;
Service中各生命周期函数执行超过20s。
用户在App的绝大部分操作,都需要有App的主动回应,比如按下按钮之后按钮样式的改变、下拉滚动条内容的移动、加载资源时的菊花转转转,它们都是“操作-反馈”配对的模式。对于我们手机上最常见的触摸操作,0.1s的响应延迟已经有很明显的卡顿感了。而对于常见的ANR,用户至少要等5s以上!
发生了ANR,往往会弹出对话框,问用户是继续等待还是直接关掉:
相信几乎所有Android手机用户都见过这个然并卵的ANR对话框,但大部分普通用户根本不知道这个对话框在讲什么,并且往往也只有关闭App。漫长的等待就给我看这个?从用户的体验看,就是心中一万只草泥马奔腾起来撞火车的感受。可见ANR对于应用的影响并不亚于Crash。
一般来说,界面相对越不“流畅”的App(说明UI线程耗时操作多)越容易发生ANR(一个输入事件在某个设备A上4秒有了反馈,并不意味着它在其他设备B上是安全的)。ANR其实就是界面卡顿的极端情况。反过来,只要通过合理的方案消灭了App出现的ANR,往往也同时会使App展示界面表现会更加顺滑流畅。
一些典型的ANR 问题场景
这里举几个容易发生ANR的场景:
1)最常见的错误,UI线程等待其它线程释放某个锁,导致UI线程无法处理用户输入;
2)游戏中每帧动画都进行了比较耗时的大量计算,导致CPU忙不过来;
3)Web应用中,网络状态不稳定,而界面在等待网络数据;
4)UI线程中进行了一些磁盘IO(包括数据库、SD卡等等)的操作,在个别设备上因为硬件损坏等原因阻塞住了;
5)手机被其他App占用着CPU,自己获取不到足够的CPU 时间片,纯属误伤。
通过ANR 日志定位问题
当ANR发生时,我们往往通过Logcat和traces文件(目录/data/anr/)的相关信息输出去定位问题。主要包含以下几方面:
1)基本信息,包括进程名、进程号、包名、系统build号、ANR 类型等等;
2)CPU使用信息,包括活跃进程的CPU 平均占用率、IO情况等等;
3)线程堆栈信息,所属进程包括发生ANR的进程、其父进程、最近有活动的3个进程等等。
这里举个简单的例子(实际上因为各App所处环境各异,可能出现各种各样复杂的ANR情况)当App运行卡住,弹出ANR对话框,查看Logcat输出:
ActivityManager: ANR in com.tencent.bugly.demo (com.tencent.bugly.demo/.MainActivity)
ActivityManager: PID: 18617
ActivityManager: Reason: Input dispatching timed out (Waiting because the touched window has not finished processing the input events that were previously delivered to it.)
ActivityManager: Load: 18.42 / 18.09 / 18.29
ActivityManager: CPU usage from 5924ms to 475ms ago:
ActivityManager: 93% 18617/com.tencent.bugly.demo: 93% user + 0% kernel / faults: 75 minor
ActivityManager: CPU usage from 2906ms to 3429ms later:
ActivityManager: 96% 18617/com.tencent.bugly.demo: 96% user + 0% kernel
ActivityManager: 55% TOTAL: 51% user + 3.8% kernel
分析一下,从Logcat可以得到以下信息:
com.tencent.bugly.demo这个App的MainActivity发生了ANR,进程号18617;
ANR原因:用户输入超时;
ANR发生前、后一段时间分别附在情况:在ANR发生前后,CPU有90+%耗费在这个demo上,说明很可能是这个demo自身性能引起的。
接下来再看traces文件确认:
----- pid 18617 at xxxx -----
Cmd line: com.tencent.bugly.demo
JNI: CheckJNI pins=0; globals=272 (plus 2 weak)
DALVIK THREADS:
&main& prio=5 tid=1 SUSPENDED
| group=&main& sCount=1 dsCount=0 obj=0x415e4e58 self=0x415d3028
| sysTid=18617 nice=0 sched=0/0 cgrp=apps handle=
| state=S schedstat=(
67 ) utm=3846 stm=12 core=0
at com.tencent.bugly.demo.MainActivity$3.doCalc(MainActivity.java:~38)
at com.tencent.bugly.demo.MainActivity$3.onClick(MainActivity.java:33)
分析一下,traces文件中包含以下信息:
1、进程号:18617;包名:com.tencent.bugly.demo;
2、发生ANR时,main线程被挂起(也可能是其他等待状态,比如TIMED_WAIT);
3、线程的几个重要参数:
group:线程组名称“main”;
sCount:Suspended个数“1”;
obj:线程的Java对象地址;
self:线程的Native对象地址;
sysTid:线程号(这里主线程的线程号=进程号)“18617”;
4、具体堆栈:从堆栈可以很清晰看出是doCalc()方法出的问题,由onClick触发。
综合以上分析,问题还原为:com.tencent.bugly.demo这个App的MainActivity中有个耗时的doCalc方法在跑,无法响应用户的触摸或按键输入。OK,接下来在代码里找问题就好了。
如何解决ANR
当然是尽可能减少UI线程的耗时操作,以及BroadcastReceiver、Service生命周期中的标准回调方法啦。
Android官方文档建议:
1)使用AsyncTask类,可以很方便地实现子线程耗时操作与UI更新;
2)对于BroadcastReceiver的耗时操作,建议放到Service中执行;
3)对于自建的Thread,可以通过Handler使之与UI 线程通信(这里需要注意的是,Thread默认优先级和UI线程是一样的,建议设置一般线程优先级为Process.THREAD_PRIORITY_BACKGROUND)。
这些方案大家应该都知道,不过仍难免有大量的ANR是写代码时忽略了,在测试时没发生,最终在用户的手机上出现的。回想一下是不是都经历过用户会反馈“App卡死没反应了”,但开发GG客服MM们却又因为缺少日志或无法复现而束手无策?因此要修复ANR,首先是要能发现用户ANR了,并且能知道是哪段代码导致ANR了,这样才能谈修复。
为了帮助广大开发者解决这一难题,腾讯Bugly针对iOS的卡顿及Android的ANR提供监测服务即将上线,协助开发者轻松定位问题。
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:&&&&&&
&&国之画&&&& &&
版权所有 京ICP备号-2
迷上了代码!当前【全部】
全部安卓手机安卓平板安卓电视iPhoneiPad其他
当前位置:>>>CPU Usage Widget
热门排行榜
1000万+人在玩9000万+人在玩1000万+人在玩9000万+人在玩1000万+人在玩1000万+人在玩
CPU Usage Widget app相关推荐
发现该应用有下载安装使用错误或恶意扣费携带病毒,请
版权所有 京ICP备号-5
京公网安备 50 备ANR log fenxi
ANR log fenxi
发布时间: 14:14:20
编辑:www.fx114.net
本篇文章主要介绍了"ANR log fenxi",主要涉及到ANR log fenxi方面的内容,对于ANR log fenxi感兴趣的同学可以参考一下。
//WindowManager所在的进程是system_server,进程号是127
I/WindowManager( 127): Input event dispatching timed out sending to com.example.anrdemo/com.example.anrdemo.ANRActivity
//system_server进程中的ActivityManagerService请求kernel向5033进程发送SIGNAL_QUIT请求
//你可以在shell中使用命令达到相同的目的:adb
shell kill -3 5033
//和其他的Java虚拟机一样,SIGNAL_QUIT也是Dalvik内部支持的功能之一
I/Process ( 127): Sending signal. PID: 5033 SIG: 3
//5033进程的虚拟机实例接收到SIGNAL_QUIT信号后会将进程中各个线程的函数堆栈信息输出到traces.txt文件中
//发生ANR的进程正常情况下会第一个输出
I/dalvikvm( 5033): threadid=4: reacting to signal 3
I/dalvikvm( 5033): Wrote stack traces to '/data/anr/traces.txt'
... ...//另外还有其他一些进程
//随后会输出CPU使用情况
E/ActivityManager( 127): ANR in com.example.anrdemo (com.example.anrdemo/.ANRActivity)
//Reason表示导致ANR问题的直接原因
E/ActivityManager( 127): Reason: keyDispatchingTimedOut
E/ActivityManager( 127): Load: 3.85 / 3.41 / 3.16
//请注意ago,表示ANR发生之前的一段时间内的CPU使用率,并不是某一时刻的值
E/ActivityManager( 127): CPU usage from 26835ms to 3662ms ago with 99% awake:
E/ActivityManager( 127): 9.4% 98/mediaserver: 9.4% user + 0% kernel
E/ActivityManager( 127): 8.9% 127/system_server: 6.9% user + 2% kernel / faults: 1823 minor
E/ActivityManager( 127): +0% 5033/com.example.anrdemo: 0% user + 0% kernel
E/ActivityManager( 127): 39% TOTAL: 32% user + 6.1% kernel
//这里是later,表示ANR发生之后
E/ActivityManager( 127): CPU usage from 601ms to 1132ms later with 99% awake:
E/ActivityManager( 127): 10% 127/system_server: 1.7% user + 8.9% kernel / faults: 5 minor
E/ActivityManager( 127): 10% 163/InputDispatcher: 1.7% user + 8.9% kernel
E/ActivityManager( 127): 1.7% 127/system_server: 1.7% user + 0% kernel
E/ActivityManager( 127): 1.7% 135/SurfaceFlinger: 0% user + 1.7% kernel
E/ActivityManager( 127): 1.7% 2814/Binder Thread #: 1.7% user + 0% kernel
E/ActivityManager( 127): 37% TOTAL: 27% user + 9.2% kernel
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, final String annotation) {
//firstPids和lastPids两个集合存放那些将会在traces中输出信息的进程的进程号
ArrayList&Integer& firstPids = new ArrayList&Integer&(5);
SparseArray&Boolean& lastPids = new SparseArray&Boolean&(20);
//mController是IActivityController接口的实例,是为Monkey测试程序预留的,默认为null
if (mController != null) {
long anrTime = SystemClock.uptimeMillis();
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow(); //更新CPU使用率
synchronized (this) { //一些特定条件下会忽略ANR
if (mShuttingDown) {
Slog.i(TAG, &During shutdown skipping ANR: & + app + & & + annotation);
} else if (app.notResponding) {
Slog.i(TAG, &Skipping duplicate ANR: & + app + & & + annotation);
} else if (app.crashing) {
Slog.i(TAG, &Crashing app skipping ANR: & + app + & & + annotation);
//使用一个标志变量避免同一个应用在没有处理完时重复输出log
app.notResponding =
//①当前发生ANR的应用进程被第一个添加进firstPids集合中
firstPids.add(app.pid);
//②dumpStackTraces是输出traces文件的函数
File tracesFile = dumpStackTraces(true, firstPids, processStats, lastPids, null);
String cpuInfo =
if (MONITOR_CPU_USAGE) { //MONITOR_CPU_USAGE默认为true
updateCpuStatsNow(); //再次更新CPU信息
synchronized (mProcessStatsThread) {
//输出ANR发生前一段时间内的CPU使用率
cpuInfo = mProcessStats.printCurrentState(anrTime);
info.append(processStats.printCurrentLoad());
info.append(cpuInfo);
//输出ANR发生后一段时间内的CPU使用率
info.append(processStats.printCurrentState(anrTime));
//③将ANR信息同时输出到DropBox中
addErrorToDropBox(&anr&, app, app.processName, activity, parent, annotation,
cpuInfo, tracesFile, null);
//在Android4.0中可以设置是否不显示ANR提示对话框,如果设置的话就不会显示对话框,并且会杀掉ANR进程
boolean showBackground = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.ANR_SHOW_BACKGROUND, 0) != 0;
synchronized (this) {
if (!showBackground && !app.isInterestingToUserLocked() && app.pid != MY_PID) {
Process.killProcessQuiet(app.pid);
显示ANR提示对话框
Message msg = Message.obtain();
HashMap map = new HashMap();
msg.what = SHOW_NOT_RESPONDING_MSG;
map.put(&app&, app);
if (activity != null) {
map.put(&activity&, activity);
mHandler.sendMessage(msg);
public static File dumpStackTraces(boolean clearTraces, ArrayList&Integer& firstPids,
ProcessStats processStats, SparseArray&Boolean& lastPids, String[] nativeProcs) {
//系统属性“dalvik.vm.stack-trace-file”用来配置trace信息输出文件
String tracesPath = SystemProperties.get(&dalvik.vm.stack-trace-file&, null);
if (tracesPath == null || tracesPath.length() == 0) {
File tracesFile = new File(tracesPath);
File tracesDir = tracesFile.getParentFile();
if (!tracesDir.exists()) tracesFile.mkdirs();
//FileUtils.setPermissions是个很有用的函数,设置文件属性时经常会用到
FileUtils.setPermissions(tracesDir.getPath(), 0775, -1, -1); // drwxrwxr-x
//clearTraces为true,会删除旧文件,创建新文件
if (clearTraces && tracesFile.exists()) tracesFile.delete();
tracesFile.createNewFile();
FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
} catch (IOException e) {
Slog.w(TAG, &Unable to prepare ANR traces file: & + tracesPath, e);
//一个重载函数
dumpStackTraces(tracesPath, firstPids, processStats, lastPids, nativeProcs);
return tracesF
getpropdalvik.vm.stack-trace-file
setprop dalvik.vm.stack-trace-file /tmp/stack-traces.txt
private static void dumpStackTraces(String tracesPath, ArrayList&Integer& firstPids,
ProcessStats processStats, SparseArray&Boolean& lastPids, String[] nativeProcs) {
//使用FileObserver监听应用进程是否已经完成写入traces文件的操作
//Android在判断桌面壁纸文件是否设置完成时也是用的FileObserver,很有用的类
FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
public synchronized void onEvent(int event, String path) { notify(); }
//首先输出firstPids集合中指定的进程,这些也是对ANR问题来说最重要的进程
if (firstPids != null) {
int num = firstPids.size();
for (int i = 0; i & i++) {
synchronized (observer) {
//前面提到的SIGNAL_QUIT
Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
observer.wait(200);
Watchdog写完后注意补充章节号 --&
Slog.i(TAG, &DropBox Service&);
ServiceManager.addService(Context.DROPBOX_SERVICE, //服务名称为“dropbox”
new DropBoxManagerService(context,
new File(&/data/system/dropbox&)));
public voidadd(DropBoxManager.Entryentry)
publicboolean
isTagEnabled(String tag)
publicsynchronized
DropBoxManager.Entry getNextEntry(String tag, long millis)
//文件中输出的第一个进程的trace信息,正是发生ANR的演示程序
//开头显示进程号、ANR发生的时间点和进程名称
----- pid 9183 at
22:20:42 -----
Cmd line: com.example.anrdemo
DALVIK THREADS: //以下是各个线程的函数堆栈信息
//mutexes表示虚拟机实例中各种线程相关对象锁的value值
(mutexes: tll=0 tsl=0 tscl=0 ghl=0 hwl=0 hwll=0)
//依次是:线程名、线程优先级、线程创建时的序号、①线程当前状态
&main& prio=5 tid=1 TIMED_WAIT
//依次是:线程组名称、suspendCount、debugSuspendCount、线程的Java对象地址、线程的Native对象地址
| group=&main& sCount=1 dsCount=0 obj=0x self=0xce68
//sysTid是线程号,主线程的线程号和进程号相同
| sysTid=9183 nice=0 sched=0/0 cgrp=default handle=-
| schedstat=(
at java.lang.VMThread.sleep(Native Method)
at java.lang.Thread.sleep(Thread.java:1213)
at java.lang.Thread.sleep(Thread.java:1195)
at com.example.anrdemo.ANRActivity.makeANR(ANRActivity.java:44)
at com.example.anrdemo.ANRActivity.onClick(ANRActivity.java:38)
at android.view.View.performClick(View.java:2486)
at android.view.View$PerformClick.run(View.java:9130)
at android.os.Handler.handleCallback(Handler.java:587)
at android.os.Handler.dispatchMessage(Handler.java:92)
at android.os.Looper.loop(Looper.java:130)
at android.app.ActivityThread.main(ActivityThread.java:3703)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:507)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:841)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:599)
at dalvik.system.NativeStart.main(Native Method)
//②Binder线程是进程的线程池中用来处理binder请求的线程
&Binder Thread #2& prio=5 tid=8 NATIVE
| group=&main& sCount=1 dsCount=0 obj=0x40750b90 self=0x1440b8
| sysTid=9190 nice=0 sched=0/0 cgrp=default handle=1476256
| schedstat=( 63135 4 )
at dalvik.system.NativeStart.run(Native Method)
&Binder Thread #1& prio=5 tid=7 NATIVE
| group=&main& sCount=1 dsCount=0 obj=0x self=0x78d40
| sysTid=9189 nice=0 sched=0/0 cgrp=default handle=1308088
| schedstat=( 43212 10 )
at dalvik.system.NativeStart.run(Native Method)
//线程名称后面标识有daemon,说明这是个守护线程
&Compiler& daemon prio=5 tid=6 VMWAIT
| group=&system& sCount=1 dsCount=0 obj=0x self=0x141e78
| sysTid=9188 nice=0 sched=0/0 cgrp=default handle=1506000
| schedstat=(
at dalvik.system.NativeStart.run(Native Method)
//JDWP线程是支持虚拟机调试的线程,不需要关心
&JDWP& daemon prio=5 tid=5 VMWAIT
| group=&system& sCount=1 dsCount=0 obj=0x self=0x16c958
| sysTid=9187 nice=0 sched=0/0 cgrp=default handle=1510224
| schedstat=( 7617 7 )
at dalvik.system.NativeStart.run(Native Method)
//“Signal Catcher”负责接收和处理kernel发送的各种信号,例如SIGNAL_QUIT、SIGNAL_USR1等就是被该线程
//接收到,这个文件的内容就是由该线程负责输出的,可以看到它的状态是RUNNABLE,不过此线程也不需要关心
&Signal Catcher& daemon prio=5 tid=4 RUNNABLE
| group=&system& sCount=0 dsCount=0 obj=0x self=0x150008
| sysTid=9186 nice=0 sched=0/0 cgrp=default handle=1501664
| schedstat=( 6621 9 )
at dalvik.system.NativeStart.run(Native Method)
&GC& daemon prio=5 tid=3 VMWAIT
| group=&system& sCount=1 dsCount=0 obj=0x self=0x168010
| sysTid=9185 nice=0 sched=0/0 cgrp=default handle=1503184
| schedstat=( 1778 2 )
at dalvik.system.NativeStart.run(Native Method)
&HeapWorker& daemon prio=5 tid=2 VMWAIT
| group=&system& sCount=1 dsCount=0 obj=0x self=0x16a080
| sysTid=9184 nice=0 sched=0/0 cgrp=default handle=550856
| schedstat=( 36669 15 )
at dalvik.system.NativeStart.run(Native Method)
----- end 9183 -----
----- pid 127 at
22:20:42 -----
Cmd line: system_server
//省略其他进程的信息
Thread.java中定义的状态
Thread.cpp中定义的状态
TERMINATED
RUNNING/RUNNABLE
TIMED_WAITING
TIMED_WAIT
INITIALIZING
线程的ThreadGroup最好也写进去 --&
E/ActivityManager( 127): ANR in com.example.anrdemo (com.example.anrdemo/.ANRActivity)
E/ActivityManager( 127): Reason: keyDispatchingTimedOut
E/ActivityManager( 127): Load: 3.85 / 3.41 / 3.16 //? CPU平均负载
//②ANR发生之前的一段时间内的CPU使用率
E/ActivityManager( 127): CPU usage from 26835ms to 3662ms ago with 99% awake://③
E/ActivityManager( 127): 9.4% 98/mediaserver: 9.4% user + 0% kernel
E/ActivityManager( 127): 8.9% 127/system_server: 6.9% user + 2% kernel / faults: 1823 minor //⑤ minor或者major的页错误次数
E/ActivityManager( 127)://⑥+0% 5033/com.example.anrdemo:
0% user + 0% kernel
E/ActivityManager( 127): 39% TOTAL: 32% user + 6.1% kernel
//⑦ANR发生之后的一段时间内的CPU使用率
E/ActivityManager( 127): CPU usage from 601ms to 1132ms later with 99% awake:
E/ActivityManager( 127): 10% 127/system_server: 1.7% user + 8.9% kernel / faults: 5 minor
E/ActivityManager( 127): 10% 163/InputDispatcher: 1.7% user + 8.9% kernel
E/ActivityManager( 127): 1.7% 127/system_server: 1.7% user + 0% kernel
E/ActivityManager( 127): 1.7% 135/SurfaceFlinger: 0% user + 1.7% kernel
E/ActivityManager( 127): 1.7% 2814/Binder Thread #: 1.7% user + 0% kernel
E/ActivityManager( 127): 37% TOTAL: 27% user + 9.2% kernel
CPU使用率=
(T – I) / T
//第一次使用成员变量mProcessStats采样
if (MONITOR_CPU_USAGE) {
updateCpuStatsNow();
//声明了一个局部变量,参数true表示包括线程信息
final ProcessStats processStats =
new ProcessStats(true);
//将processStats作为实参传入,在dumpStackTraces中相隔500毫秒两次调用其update函数进行采样
File tracesFile =
dumpStackTraces(true, firstPids, processStats, lastPids);
String cpuInfo =
if (MONITOR_CPU_USAGE)
//因为在第一次调用后,可能由于输出trace信息等操作,中间执行了较长的时间,所以有第二次使用成员变量
//mProcessStats采样,尽量使得采样时间点靠后。
//此函数中要求连续两次采样时间间隔不少于5秒,所以一般不会执行第二次采样。一旦执行,就会出现两个采样
//时间点一个在ANR发生之前,另一个在其之后,或者两个时间点都在ANR发生之后的情况。
updateCpuStatsNow();
synchronized (mProcessStatsThread)
//mProcessStats是成员变量,创建对象时传入的参数是false,所以不包括线程信息
//此处先输出ANR发生之前一段时间内的CPU使用率
mProcessStats.printCurrentState(anrTime);
info.append(processStats.printCurrentLoad());
info.append(cpuInfo);
//processStats对象是在ANR发生后创建并采样的,所以输出的是ANR发生之后一段时间内的CPU使用率
info.append(processStats.printCurrentState(anrTime));
。一个文件第一次被读写时会有很多的
求证一下 --&
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:Android ANR原理分析 - Sun‘刺眼的博客 - 博客园
随笔 - 727, 文章 - 0, 评论 - 14, 引用 - 0
ANR(Application Not responding),是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。一般地,这时往往会弹出一个提示框,告知用户当前xxx未响应,用户可选择继续等待或者Force Close。
那么哪些场景会造成ANR呢?
Service Timeout:服务在20s内未执行完成;
BroadcastQueue Timeout:比如前台广播在10s内执行完成
ContentProvider Timeout:内容提供者执行超时
inputDispatching Timeout: 输入事件分发超时5s,包括按键分发事件的超时。
二、ANR触发时机
Service Timeout触发时机,简单说就是AMS中的mHandler收到SERVICE_TIMEOUT_MSG消息时触发。
在前面文章详细介绍Service启动流程,在Service所在进程attach到system_server进程的过程中会调用realStartServiceLocked()方法
2.1.1 realStartServiceLocked
[-& ActiveServices.java]
private final void realStartServiceLocked(ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
2.1.2 bumpServiceExecutingLocked
该方法的主要工作发送delay消息(SERVICE_TIMEOUT_MSG)
private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
scheduleServiceTimeoutLocked(r.app);
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
long now = SystemClock.uptimeMillis();
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
对于前台服务,则超时为SERVICE_TIMEOUT,即timeout=20s;
对于后台服务,则超时为SERVICE_BACKGROUND_TIMEOUT,即timeout=200s;
2.1.3 serviceDoneExecutingLocked
该方法的主要工作是当service启动完成,则移除service Timeout消息。
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing) {
if (r.executeNesting &= 0) {
if (r.app != null) {
r.app.execServicesFg =
r.app.executingServices.remove(r);
if (r.app.executingServices.size() == 0) {
到此不难理解,当SERVICE_TIMEOUT_MSG消息成功发送时,则AMS中的mHandler收到该消息则触发调用serviceTimeout。
final class MainHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case SERVICE_TIMEOUT_MSG: {
[-& ActiveServices.java]
void serviceTimeout(ProcessRecord proc) {
String anrMessage =
synchronized(mAm) {
if (proc.executingServices.size() == 0 || proc.thread == null) {
final long now = SystemClock.uptimeMillis();
final long maxTime =
(proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout =
long nextTime = 0;
for (int i=proc.executingServices.size()-1; i&=0; i--) {
ServiceRecord sr = proc.executingServices.valueAt(i);
if (sr.executingStart & maxTime) {
if (sr.executingStart & nextTime) {
nextTime = sr.executingS
if (timeout != null && mAm.mLruProcesses.contains(proc)) {
Slog.w(TAG, "Timeout executing service: " + timeout);
StringWriter sw = new StringWriter();
PrintWriter pw = new FastPrintWriter(sw, false, 1024);
pw.println(timeout);
timeout.dump(pw, "
pw.close();
mLastAnrDump = sw.toString();
mAm.mHandler.removeCallbacks(mLastAnrDumpClearer);
mAm.mHandler.postDelayed(mLastAnrDumpClearer, LAST_ANR_LIFETIME_DURATION_MSECS);
anrMessage = "executing service " + timeout.shortN
if (anrMessage != null) {
其中anrMessage的内容为&executing service [发送超时serviceRecord信息]&;
BroadcastQueue Timeout触发时机,简单说就是BroadcastQueue中的mHandler收到BROADCAST_TIMEOUT_MSG消息时触发。
在前面文章详细介绍广播启动流程,在发送广播过程中会执行scheduleBroadcastsLocked方法来处理相关的广播,然后会调用到processNextBroadcast方法来处理下一条广播。
processNextBroadcast执行过程分4步骤:
step1. 处理并行广播
step2. 处理当前有序广播
step3. 获取下条有序广播
step4. 处理下条有序广播
2.2.1 processNextBroadcast
[-& BroadcastQueue.java]
final void processNextBroadcast(boolean fromMsg) {
synchronized(mService) {
对于广播超时处理时机:
首先在step3的过程中setBroadcastTimeoutLocked(timeoutTime) 设置超时广播消息;
然后在step2根据广播处理情况来处理:
当广播接收者等待时间过长,则调用broadcastTimeoutLocked(false);
当,cancelBroadcastTimeoutLocked
final void setBroadcastTimeoutLocked(long timeoutTime) {
if (! mPendingBroadcastTimeoutMessage) {
Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
mHandler.sendMessageAtTime(msg, timeoutTime);
mPendingBroadcastTimeoutMessage =
设置定时广播BROADCAST_TIMEOUT_MSG,即当前往后推mTimeoutPeriod时间广播还没处理完毕,则进入广播超时流程。
对于前台广播,则超时为BROADCAST_FG_TIMEOUT,即timeout=10s;
对于后台广播,则超时为BROADCAST_BG_TIMEOUT,即timeout=60s。
final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage =
移除广播超时消息BROADCAST_TIMEOUT_MSG
到此不难理解,当BROADCAST_TIMEOUT_MSG消息成功发送时,则AMS中的mHandler收到该消息则触发调用serviceTimeout。
private final class BroadcastHandler extends Handler {
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
[-& BroadcastRecord.java]
final void broadcastTimeoutLocked(boolean fromMsg) {
if (fromMsg) {
mPendingBroadcastTimeoutMessage =
if (mOrderedBroadcasts.size() == 0) {
long now = SystemClock.uptimeMillis();
BroadcastRecord r = mOrderedBroadcasts.get(0);
if (fromMsg) {
if (mService.mDidDexOpt) {
2.2.6 AppNotResponding
[-& BroadcastQueue.java]
private final class AppNotResponding implements Runnable {
public void run() {
2.3.1 AMS.appNotRespondingViaProvider
public void appNotRespondingViaProvider(IBinder connection) {
enforceCallingPermission(
android.Manifest.permission.REMOVE_TASKS, "appNotRespondingViaProvider()");
final ContentProviderConnection conn = (ContentProviderConnection)
if (conn == null) {
final ProcessRecord host = conn.provider.
Timeout时间20s
在native层InputDispatcher.cpp中经过层层调用,此处先省略过程,后续再展开,从native层com_android_server_input_InputManagerService调用到java层InputManagerService。
2.4.1 IMS.notifyANR
[-& InputManagerService.java]
private long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
mWindowManagerCallbacks为InputMonitor对象
2.4.2 notifyANR
[-& InputMonitor.java]
public long notifyANR(InputApplicationHandle inputApplicationHandle,
InputWindowHandle inputWindowHandle, String reason) {
AppWindowToken appWindowToken =
WindowState windowState =
boolean aboveSystem =
synchronized (mService.mWindowMap) {
if (inputWindowHandle != null) {
windowState = (WindowState) inputWindowHandle.windowS
if (windowState != null) {
appWindowToken = windowState.mAppT
if (appWindowToken == null && inputApplicationHandle != null) {
appWindowToken = (AppWindowToken)inputApplicationHandle.appWindowT
public long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) {
synchronized (this) {
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(pid);
inputDispatching的超时为KEY_DISPATCHING_TIMEOUT,即timeout = 5s
public boolean inputDispatchingTimedOut(final ProcessRecord proc,
final ActivityRecord activity, final ActivityRecord parent,
final boolean aboveSystem, String reason) {
if (reason == null) {
annotation = "Input dispatching timed out";
annotation = "Input dispatching timed out (" + reason + ")";
if (proc != null) {
mHandler.post(new Runnable() {
public void run() {
keyDispatching timout与inputDispatching Timeout流畅基本一致。
[-& ActivityRecord.java]
final class ActivityRecord {
static class Token extends IApplicationToken.Stub {
public boolean keyDispatchingTimedOut(String reason) {
ActivityRecord anrA
ProcessRecord anrA
synchronized (mService) {
r = tokenToActivityRecordLocked(this);
if (r == null) {
anrActivity = r.getWaitingHistoryRecordLocked();
anrApp = r != null ? r.app :
return mService.inputDispatchingTimedOut(anrApp, anrActivity, r, false, reason);
对于keyDispatching Timeout的ANR,当触发该类型ANR时,如果不再有输入事件,则不会弹出ANR对话框;只有在下一次input事件产生后5s才弹出ANR提示框。
三、ANR工作
3.1 appNotResponding
[-& ActivityManagerService.java]
final void appNotResponding(ProcessRecord app, ActivityRecord activity,
ActivityRecord parent, boolean aboveSystem, final String annotation) {
ArrayList&Integer& firstPids = new ArrayList&Integer&(5);
SparseArray&Boolean& lastPids = new SparseArray&Boolean&(20);
if (mController != null) {
主要发送ANR, 则会输出
各个进程的CPU使用情况;
traces文件
导致ANR常见情形:
网络阻塞;
onReceiver执行时间超过10s;
多线程死锁
UI线程尽量只做跟UI相关的工作
耗时的工作()比如数据库操作,I/O,网络操作),采用单独的工作线程处理
用Handler来处理UIthread和工作thread的交互
UI线程,例如:
Activity:onCreate(), onResume(), onDestroy(), onKeyDown(), onClick(),etc
AsyncTask: onPreExecute(), onProgressUpdate(), onPostExecute(), onCancel,etc
Mainthread handler: handleMessage(), post*(runnable r), etc
ANR分析:需要关注CPU/IO,trace死锁等数据。

我要回帖

更多关于 linux cpu usage 的文章

 

随机推荐