赞
踩
ANR(Application Not responding),是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。一般地,这时往往会弹出一个提示框,告知用户当前xxx未响应,用户可选择继续等待或者Force Close。
那么哪些场景会造成ANR呢?
触发ANR的过程可分为三个步骤: 埋炸弹, 拆炸弹, 引爆炸弹
Service Timeout是位于”ActivityManager”线程中的AMS.MainHandler收到SERVICE_TIMEOUT_MSG
消息时触发。
对于Service有两类:
由变量ProcessRecord.execServicesFg来决定是否前台启动
Service进程attach到system_server进程的过程中会调用realStartServiceLocked()
方法来埋下炸弹.
[-> ActiveServices.java]
- private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException {
- ...
- //发送delay消息(SERVICE_TIMEOUT_MSG),【见小节2.1.2】
- bumpServiceExecutingLocked(r, execInFg, "create");
- try {
- ...
- //最终执行服务的onCreate()方法
- app.thread.scheduleCreateService(r, r.serviceInfo,
- mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
- app.repProcState);
- } catch (DeadObjectException e) {
- mAm.appDiedLocked(app);
- throw e;
- } finally {
- ...
- }
- }
- 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) {
- return;
- }
- long now = SystemClock.uptimeMillis();
- Message msg = mAm.mHandler.obtainMessage(
- ActivityManagerService.SERVICE_TIMEOUT_MSG);
- msg.obj = proc;
-
- //当超时后仍没有remove该SERVICE_TIMEOUT_MSG消息,则执行service Timeout流程【见2.3.1】
- mAm.mHandler.sendMessageAtTime(msg,
- proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
- }
该方法的主要工作发送delay消息(SERVICE_TIMEOUT_MSG
). 炸弹已埋下, 我们并不希望炸弹被引爆, 那么就需要在炸弹爆炸之前拆除炸弹.
在system_server进程AS.realStartServiceLocked()调用的过程会埋下一颗炸弹, 超时没有启动完成则会爆炸. 那么什么时候会拆除这颗炸弹的引线呢? 经过Binder等层层调用进入目标进程的主线程handleCreateService()的过程.
[-> ActivityThread.java]
- private void handleCreateService(CreateServiceData data) {
- ...
- java.lang.ClassLoader cl = packageInfo.getClassLoader();
- Service service = (Service) cl.loadClass(data.info.name).newInstance();
- ...
-
- try {
- //创建ContextImpl对象
- ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
- context.setOuterContext(service);
- //创建Application对象
- Application app = packageInfo.makeApplication(false, mInstrumentation);
- service.attach(context, this, data.info.name, data.token, app,
- ActivityManagerNative.getDefault());
- //调用服务onCreate()方法
- service.onCreate();
-
- //拆除炸弹引线[见小节2.2.2]
- ActivityManagerNative.getDefault().serviceDoneExecuting(
- data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
- } catch (Exception e) {
- ...
- }
- }
在这个过程会创建目标服务对象,以及回调onCreate()方法, 紧接再次经过多次调用回到system_server来执行serviceDoneExecuting.
- private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying, boolean finishing) {
- ...
- if (r.executeNesting <= 0) {
- if (r.app != null) {
- r.app.execServicesFg = false;
- r.app.executingServices.remove(r);
- if (r.app.executingServices.size() == 0) {
- //当前服务所在进程中没有正在执行的service
- mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
- ...
- }
- ...
- }
该方法的主要工作是当service启动完成,则移除服务超时消息SERVICE_TIMEOUT_MSG
。
前面介绍了埋炸弹和拆炸弹的过程, 如果在炸弹倒计时结束之前成功拆卸炸弹,那么就没有爆炸的机会, 但是世事难料. 总有些极端情况下无法即时拆除炸弹,导致炸弹爆炸, 其结果就是App发生ANR. 接下来,带大家来看看炸弹爆炸的现场:
在system_server进程中有一个Handler线程, 名叫”ActivityManager”.当倒计时结束便会向该Handler线程发送 一条信息SERVICE_TIMEOUT_MSG
,
[-> ActivityManagerService.java ::MainHandler]
- final class MainHandler extends Handler {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case SERVICE_TIMEOUT_MSG: {
- ...
- //【见小节2.3.2】
- mServices.serviceTimeout((ProcessRecord)msg.obj);
- } break;
- ...
- }
- ...
- }
- }
- void serviceTimeout(ProcessRecord proc) {
- String anrMessage = null;
-
- synchronized(mAm) {
- if (proc.executingServices.size() == 0 || proc.thread == null) {
- return;
- }
- final long now = SystemClock.uptimeMillis();
- final long maxTime = now -
- (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
- ServiceRecord timeout = null;
- long nextTime = 0;
- for (int i=proc.executingServices.size()-1; i>=0; i--) {
- ServiceRecord sr = proc.executingServices.valueAt(i);
- if (sr.executingStart < maxTime) {
- timeout = sr;
- break;
- }
- if (sr.executingStart > nextTime) {
- nextTime = sr.executingStart;
- }
- }
- 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.shortName;
- }
- }
-
- if (anrMessage != null) {
- //当存在timeout的service,则执行appNotResponding
- mAm.appNotResponding(proc, null, null, false, anrMessage);
- }
- }
其中anrMessage的内容为”executing service [发送超时serviceRecord信息]”;
BroadcastReceiver Timeout是位于”ActivityManager”线程中的BroadcastQueue.BroadcastHandler收到BROADCAST_TIMEOUT_MSG
消息时触发。
对于广播队列有两个: foreground队列和background队列:
广播启动通过调用 processNextBroadcast来处理广播.其流程为先处理并行广播,再处理当前有序广播,最后获取并处理下条有序广播.
[-> BroadcastQueue.java]
- final void processNextBroadcast(boolean fromMsg) {
- synchronized(mService) {
- ...
- //part 2: 处理当前有序广播
- do {
- r = mOrderedBroadcasts.get(0);
- //获取所有该广播所有的接收者
- int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
- if (mService.mProcessesReady && r.dispatchTime > 0) {
- long now = SystemClock.uptimeMillis();
- if ((numReceivers > 0) &&
- (now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
- //当广播处理时间超时,则强制结束这条广播【见小节3.3.2】
- broadcastTimeoutLocked(false);
- ...
- }
- }
- if (r.receivers == null || r.nextReceiver >= numReceivers
- || r.resultAbort || forceReceive) {
- if (r.resultTo != null) {
- //处理广播消息消息
- performReceiveLocked(r.callerApp, r.resultTo,
- new Intent(r.intent), r.resultCode,
- r.resultData, r.resultExtras, false, false, r.userId);
- r.resultTo = null;
- }
- //拆炸弹【见小节3.2.2】
- cancelBroadcastTimeoutLocked();
- }
- } while (r == null);
- ...
-
- //part 3: 获取下条有序广播
- r.receiverTime = SystemClock.uptimeMillis();
- if (!mPendingBroadcastTimeoutMessage) {
- long timeoutTime = r.receiverTime + mTimeoutPeriod;
- //埋炸弹【见小节3.1.2】
- setBroadcastTimeoutLocked(timeoutTime);
- }
- ...
- }
- }
对于广播超时处理时机:
- final void setBroadcastTimeoutLocked(long timeoutTime) {
- if (! mPendingBroadcastTimeoutMessage) {
- Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
- mHandler.sendMessageAtTime(msg, timeoutTime);
- mPendingBroadcastTimeoutMessage = true;
- }
- }
设置定时广播BROADCAST_TIMEOUT_MSG,即当前往后推mTimeoutPeriod时间广播还没处理完毕,则进入广播超时流程。
broadcast跟service超时机制大抵相同,但有一个非常隐蔽的技能点,那就是通过静态注册的广播超时会受SharedPreferences(简称SP)的影响。
关于广播是否考虑SP的情况取决于如下代码:
- public final void finish() {
- if (mType == TYPE_COMPONENT) {
- final IActivityManager mgr = ActivityManager.getService();
- if (QueuedWork.hasPendingWork()) {
- //当SP有未同步到磁盘的工作,则需等待其完成,才告知系统已完成该广播
- QueuedWork.queue(new Runnable() {
- public void run() {
- sendFinished(mgr);
- }
- }, false);
- } else {
- sendFinished(mgr);
- }
- } else if (mOrderedHint && mType != TYPE_UNREGISTERED) {
- final IActivityManager mgr = ActivityManager.getService();
- sendFinished(mgr);
- }
- }
可见,只有XML静态注册的广播超时检测过程会考虑是否有SP尚未完成,动态广播并不受其影响。
- final void cancelBroadcastTimeoutLocked() {
- if (mPendingBroadcastTimeoutMessage) {
- mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
- mPendingBroadcastTimeoutMessage = false;
- }
- }
移除广播超时消息BROADCAST_TIMEOUT_MSG
[-> BroadcastQueue.java ::BroadcastHandler]
- private final class BroadcastHandler extends Handler {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case BROADCAST_TIMEOUT_MSG: {
- synchronized (mService) {
- //【见小节3.3.2】
- broadcastTimeoutLocked(true);
- }
- } break;
- ...
- }
- ...
- }
- }
[-> BroadcastRecord.java]
- //fromMsg = true
- final void broadcastTimeoutLocked(boolean fromMsg) {
- if (fromMsg) {
- mPendingBroadcastTimeoutMessage = false;
- }
-
- if (mOrderedBroadcasts.size() == 0) {
- return;
- }
-
- long now = SystemClock.uptimeMillis();
- BroadcastRecord r = mOrderedBroadcasts.get(0);
- if (fromMsg) {
- if (mService.mDidDexOpt) {
- mService.mDidDexOpt = false;
- long timeoutTime = SystemClock.uptimeMillis() + mTimeoutPeriod;
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
-
- if (!mService.mProcessesReady) {
- return; //当系统还没有准备就绪时,广播处理流程中不存在广播超时
- }
-
- long timeoutTime = r.receiverTime + mTimeoutPeriod;
- if (timeoutTime > now) {
- //如果当前正在执行的receiver没有超时,则重新设置广播超时
- setBroadcastTimeoutLocked(timeoutTime);
- return;
- }
- }
-
- BroadcastRecord br = mOrderedBroadcasts.get(0);
- if (br.state == BroadcastRecord.WAITING_SERVICES) {
- //广播已经处理完成,但需要等待已启动service执行完成。当等待足够时间,则处理下一条广播。
- br.curComponent = null;
- br.state = BroadcastRecord.IDLE;
- processNextBroadcast(false);
- return;
- }
-
- r.receiverTime = now;
- //当前BroadcastRecord的anr次数执行加1操作
- r.anrCount++;
-
- if (r.nextReceiver <= 0) {
- return;
- }
- ...
-
- Object curReceiver = r.receivers.get(r.nextReceiver-1);
- //查询App进程
- if (curReceiver instanceof BroadcastFilter) {
- BroadcastFilter bf = (BroadcastFilter)curReceiver;
- if (bf.receiverList.pid != 0
- && bf.receiverList.pid != ActivityManagerService.MY_PID) {
- synchronized (mService.mPidsSelfLocked) {
- app = mService.mPidsSelfLocked.get(
- bf.receiverList.pid);
- }
- }
- } else {
- app = r.curApp;
- }
-
- if (app != null) {
- anrMessage = "Broadcast of " + r.intent.toString();
- }
-
- if (mPendingBroadcast == r) {
- mPendingBroadcast = null;
- }
-
- //继续移动到下一个广播接收者
- finishReceiverLocked(r, r.resultCode, r.resultData,
- r.resultExtras, r.resultAbort, false);
- scheduleBroadcastsLocked();
-
- if (anrMessage != null) {
- // [见小节3.3.3]
- mHandler.post(new AppNotResponding(app, anrMessage));
- }
- }
[-> BroadcastQueue.java]
- private final class AppNotResponding implements Runnable {
- ...
- public void run() {
- // 进入ANR处理流程
- mService.appNotResponding(mApp, null, null, false, mAnnotation);
- }
- }
ContentProvider Timeout是位于”ActivityManager”线程中的AMS.MainHandler收到CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息时触发。
ContentProvider 超时为CONTENT_PROVIDER_PUBLISH_TIMEOUT = 10s. 这个跟前面的Service和BroadcastQueue完全不同, 由Provider进程启动过程相关.
埋炸弹的过程 其实是在进程创建的过程,进程创建后会调用attachApplicationLocked()进入system_server进程.
- private final boolean attachApplicationLocked(IApplicationThread thread, int pid) {
- ProcessRecord app;
- if (pid != MY_PID && pid >= 0) {
- synchronized (mPidsSelfLocked) {
- app = mPidsSelfLocked.get(pid); // 根据pid获取ProcessRecord
- }
- }
- ...
-
- //系统处于ready状态或者该app为FLAG_PERSISTENT进程则为true
- boolean normalMode = mProcessesReady || isAllowedWhileBooting(app.info);
- List<ProviderInfo> providers = normalMode ? generateApplicationProvidersLocked(app) : null;
-
- //app进程存在正在启动中的provider,则超时10s后发送CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG消息
- if (providers != null && checkAppInLaunchingProvidersLocked(app)) {
- Message msg = mHandler.obtainMessage(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG);
- msg.obj = app;
- mHandler.sendMessageDelayed(msg, CONTENT_PROVIDER_PUBLISH_TIMEOUT);
- }
-
- thread.bindApplication(...);
- ...
- }
10s之后引爆该炸弹
当provider成功publish之后,便会拆除该炸弹.
- public final void publishContentProviders(IApplicationThread caller, List<ContentProviderHolder> providers) {
- ...
-
- synchronized (this) {
- final ProcessRecord r = getRecordForAppLocked(caller);
-
- final int N = providers.size();
- for (int i = 0; i < N; i++) {
- ContentProviderHolder src = providers.get(i);
- ...
- ContentProviderRecord dst = r.pubProviders.get(src.info.name);
- if (dst != null) {
- ComponentName comp = new ComponentName(dst.info.packageName, dst.info.name);
-
- mProviderMap.putProviderByClass(comp, dst); //将该provider添加到mProviderMap
- String names[] = dst.info.authority.split(";");
- for (int j = 0; j < names.length; j++) {
- mProviderMap.putProviderByName(names[j], dst);
- }
-
- int launchingCount = mLaunchingProviders.size();
- int j;
- boolean wasInLaunchingProviders = false;
- for (j = 0; j < launchingCount; j++) {
- if (mLaunchingProviders.get(j) == dst) {
- //将该provider移除mLaunchingProviders队列
- mLaunchingProviders.remove(j);
- wasInLaunchingProviders = true;
- j--;
- launchingCount--;
- }
- }
- //成功pubish则移除该消息
- if (wasInLaunchingProviders) {
- mHandler.removeMessages(CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG, r);
- }
- synchronized (dst) {
- dst.provider = src.provider;
- dst.proc = r;
- //唤醒客户端的wait等待方法
- dst.notifyAll();
- }
- ...
- }
- }
- }
- }
在system_server进程中有一个Handler线程, 名叫”ActivityManager”.当倒计时结束便会向该Handler线程发送 一条信息CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG
,
[-> ActivityManagerService.java ::MainHandler]
- final class MainHandler extends Handler {
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case CONTENT_PROVIDER_PUBLISH_TIMEOUT_MSG: {
- ...
- ProcessRecord app = (ProcessRecord)msg.obj;
- synchronized (ActivityManagerService.this) {
- //【见小节4.3.2】
- processContentProviderPublishTimedOutLocked(app);
- }
- } break;
- ...
- }
- ...
- }
- }
- private final void processContentProviderPublishTimedOutLocked(ProcessRecord app) {
- //[见4.3.3]
- cleanupAppInLaunchingProvidersLocked(app, true);
- //[见小节4.3.4]
- removeProcessLocked(app, false, true, "timeout publishing content providers");
- }
- boolean cleanupAppInLaunchingProvidersLocked(ProcessRecord app, boolean alwaysBad) {
- boolean restart = false;
- for (int i = mLaunchingProviders.size() - 1; i >= 0; i--) {
- ContentProviderRecord cpr = mLaunchingProviders.get(i);
- if (cpr.launchingApp == app) {
- if (!alwaysBad && !app.bad && cpr.hasConnectionOrHandle()) {
- restart = true;
- } else {
- //移除死亡的provider
- removeDyingProviderLocked(app, cpr, true);
- }
- }
- }
- return restart;
- }
removeDyingProviderLocked()的功能跟进程的存活息息相关:详见ContentProvider引用计数 []小节4.5]
- private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart, boolean allowRestart, String reason) {
- final String name = app.processName;
- final int uid = app.uid;
-
- //移除mProcessNames中的相应对象
- removeProcessNameLocked(name, uid);
- if (mHeavyWeightProcess == app) {
- mHandler.sendMessage(mHandler.obtainMessage(CANCEL_HEAVY_NOTIFICATION_MSG,
- mHeavyWeightProcess.userId, 0));
- mHeavyWeightProcess = null;
- }
- boolean needRestart = false;
- if (app.pid > 0 && app.pid != MY_PID) {
- int pid = app.pid;
- synchronized (mPidsSelfLocked) {
- mPidsSelfLocked.remove(pid);
- mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
- }
-
- ...
- boolean willRestart = false;
- if (app.persistent && !app.isolated) {
- if (!callerWillRestart) {
- willRestart = true;
- } else {
- needRestart = true;
- }
- }
- app.kill(reason, true); //杀进程
- handleAppDiedLocked(app, willRestart, allowRestart);
- if (willRestart) {
- removeLruProcessLocked(app);
- addAppLocked(app.info, false, null /* ABI override */);
- }
- } else {
- mRemovedProcesses.add(app);
- }
- return needRestart;
- }
当出现ANR时,都是调用到AMS.appNotResponding()方法手机信息
Service超时检测机制:
BroadcastReceiver超时检测机制:
另外:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。