traces是什么文件

2023-03-24 17:48 31次浏览 攻略

anr的全称是application not responding,根据它的意思我们就能看出来是应用程序未响应,就像是我们在电脑上碰到的程序未响应,一般电脑出现这种情况,可能是由于我们打开了很多应用程序,占用了大量的内存,或者CPU时间片被一个应用程序长时间占用,不够分配,导致部分应用程序出现了无响应。Android和Windows基本一样,接下来我们就分析一下Android是怎么产生的这个问题。

下图就是我们见到的APP无响应的时候出现的对话框,产生ANR的原因很多,但是只有在Activty中的Anr才会弹出对话框,对话框有两个选项,一个是等待,一个是关闭程序供用户选择:

ANR

一、为什么会产生ANR(Application not response)这种情况呢?

在Android里, App的响应能力是由Activity Manager和Window Manager系统服务来监控的.,通常情况下产生ANR有这么三个条件:

1.只有主线程才会产生ANR,主线程就是UI线程;

2.必须发生某些输入事件或特定操作,比如按键或触屏等输入事件,在BroadcastReceiver或service的各个生命周期调用函数;

3.上述事件响应超时,不同的context规定的上限时间不同

具备了以上三个条件,那么加上这两个环境,就会产生ANR了:

1.5秒内无法对输入事件(按键及触摸)做出响应

2.广播接收器无法在10秒内结束运行

二、ANR时系统做了什么

1.弹出一个对话框

2.将ANR信息输出到文件中

文件是一个ANR记录文件,用于开发人员调试,目录位于/data/anr中,无需root权限即可通过pull命令获取,下面的命令可以将文件拷贝到当前目录下

adb pull /data/anr

3.将ANR信息输出到Logcat中

ANR

三、对ANR产生详细分析

为什么会产生ANR,在第一条讲解中,具体剖析(部分文章参考简书作者):

a.主线程对输入事件5秒内没有处理完毕

b.主线程在执行BroadcastReceiver的onReceive()函数时10秒内没有处理完毕

c.主线程在Service的各个生命周期函数时20秒内没有处理完毕。

那么导致ANR的根本原因是什么呢?简单的总结有以下两点:

1.主线程执行了耗时操作,比如数据库操作或网络编程

2.其他进程(就是其他程序)占用CPU导致本进程得不到CPU时间片,比如其他进程的频繁读写操作可能会导致这个问题。

细分的话,导致ANR的原因有如下几点:

1.耗时的网络访问

2.大量的数据读写

3.数据库操作

4.硬件操作(比如camera)

5.调用thread的join()方法、sleep()方法、wait()方法或者等待线程锁的时候

6.service binder的数量达到上限

7.system server中发生WatchDog ANR

8.service忙导致超时无响应

9.其他线程持有锁,导致主线程等待超时

10.其它线程终止或崩溃导致主线程一直等待。

四、ANR机制的实现原理:

文章:从源码角度详细的分析了ANR机制实现的原理。对于上一章讲到的1-4中情况,分别找到了其源码中是如何实现的,对于每一种大概原理如下:1.在进行相关操作调用()发送一个ANR的消息,延时时间为ANR发生的时间(如前台Service是当前时间20s之后)。2.进行相关的操作3.操作结束后向remove掉该条message。如果相关的操作在规定时间没有执行完成,该条message将被handler取出并执行,就发生了ANR。

下面以BroadcastReceiver为例详细介绍:

Broadca()

final void processNextBroadcast(boolean fromMsg) { … synchronized (mService) { … do { if () == 0) { … if && r.dispatchTime > 0) { long now = Sy(); if ((numReceivers > 0) && (now > r.dispatchTime + (2 * mTimeoutPeriod * numReceivers))) { //1.发送延时消息 broadcastTimeoutLocked(false); // forcibly finish this broadcast forceReceive = true; r.state = Broadca; } } if != Broadca) { if (DEBUG_BROADCAST) Slog.d(TAG, "processNextBroadcast(" + mQueueName + ") called when not idle (state=" + r.state + ")"); return; } if == null || r.nextReceiver >= numReceivers || r.resultAbort || forceReceive) { // No more receivers for this broadcast! Send the final // result if requested… if != null) { try { //2. 处理广播消息 performReceiveLocked, r.resultTo, new Inten), r.resultCode, r.resultData, r.resultExtras, false, false, r.userId); // Set this to null so that the reference // (local and remote) isn't kept in the mBroadcastHistory. r.resultTo = null; } catch (RemoteException e) { … } } //3.取消延时消息 cancelBroadcastTimeoutLocked(); … } } while (r == null) ; … } } }
1.发送延时消息:broadcastTimeoutLocked(false): final void broadcastTimeoutLocked(boolean fromMsg) { … long now = Sy(); if (fromMsg) { if ) { // Delay timeouts until dexopt finishes. mService.mDidDexOpt = false; long timeoutTime = Sy() + mTimeoutPeriod; setBroadcastTimeoutLocked(timeoutTime); return; } if (!mService.mProcessesReady) { return; } long timeoutTime = r.receiverTime + mTimeoutPeriod; if (timeoutTime > now) { setBroadcastTimeoutLocked(timeoutTime); return; } }
他调用了setBroadcastTimeoutLocked(long timeoutTime): final void setBroadcastTimeoutLocked(long timeoutTime) { if (! mPendingBroadcastTimeoutMessage) { Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this); mHandler.sendMessageAtTime(msg, timeoutTime); mPendingBroadcastTimeoutMessage = true; } }
传入setBroadcastTimeoutLocked(long timeoutTime)的时间xxx + mTimeoutPeriod,mTimeoutPeriod就是onRecieve()可以执行的时间,在BroadcastQueue初始化时候被赋值,前台队列为10s后台队列为60s:
Ac: public ActivityManagerService(Context systemContext) { … static final int BROADCAST_FG_TIMEOUT = 10 * 1000; static final int BROADCAST_BG_TIMEOUT = 60 * 1000; … mFgBroadcastQueue = new BroadcastQueue(this, mHandler, "foreground", BROADCAST_FG_TIMEOUT, false); mBgBroadcastQueue = new BroadcastQueue(this, mHandler, "background", BROADCAST_BG_TIMEOUT, true); … }

  1. performReceiveLocked()为广播的实际处理,就不展开了

  2. cancelBroadcastTimeoutLocked() :

    该方法的主要工作是当service启动完成,则移除服务超时消息SERVICE_TIMEOUT_MSG。

final void cancelBroadcastTimeoutLocked() {
if (mPendingBroadcastTimeoutMessage) {
mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
mPendingBroadcastTimeoutMessage = false;
}

五、如何避免ANR呢?

1.避免在主线程执行耗时操作,所有耗时操作应新开一个子线程完成,然后再在主线程更新UI。

2.BroadcastReceiver要执行耗时操作时应启动一个service,将耗时操作交给service来完成。

3.避免在Intent Receiver里启动一个Activity,因为它会创建一个新的画面,并从当前用户正在运行的程序上抢夺焦点。如果你的应用程序在响应Intent广 播时需要向用户展示什么,你应该使用Notification Manager来实现。

  • 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死锁等数据。

六、总结

ANR在我们开发APP中也比较常见,总的来说,我们需要执行耗时得操作就在子线程中执行,避免在主线程中执行。

相关推荐