• 1

  • 474

Android Service ANR 的监控机制

Mellon

大家好

2星期前

Android系统中,ANR机制是一个比较大的话题。四大组件Activity、Service、BroadCastReceiver、ContentProvider都会涉及到。四大组件对于Anr的监控机制是不尽相同的,BroadCastReceiver和Service比较类似。Activity作为强交互的组件,有一套基于InputDispatcher的独特Anr检测机制,涉及JNI层。在这里我们的重点是:针对Service组件,在Android 系统层是如何建立Anr机制的。这里的话题涵盖以下方面:

  1. Service 的 Anr监控机制都由那些重量级角色参与
  2. Service 的 Anr监控机制的建立流程是怎样的
  3. Service 的 Anr监控机制的实现原理是什么

我们一般启动一个Service,会调用startService(),我们追进去发现,调用这句话的其实是ContextImpl这个类。ContextImpl前面我们已经讲过了,是Context的子类,跟ContextWrapper是兄弟关系。然后,它调用自己的startServiceCommon()跨进程调用到sys_server进程中的ActivityManagerService(后续简称AMS)的startService()方法申请资源。在AMS 的startService()中,又调用到ActiveServices类(后续简称AS)中的startServiceLocked(),依次经历startServiceInnerLocked()->bringUpServiceLocked()->realStartServiceLocked()去真正执行startService的操作。

在realStartServiceLocked()中,首先执行bumpServiceExecutingLocked(),走到scheduleServiceTimeoutLocked()方法,就是在这里,Anr的监控机制,通过AMS中的Handler,埋下了一颗“延时炸弹”,并通过区分Service的前后台情况,选用不同的“引爆时长”。如果是ForegroundService,则超时时长为20s,后台则相对长一些,200s

void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        if (proc.executingServices.size() == 0 || proc.thread == null) {
            return;
        }
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
        mAm.mHandler.sendMessageDelayed(msg,
                proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
    }
复制代码

到此,Anr机制在监控Service startService时的第一步已经迈出了,那就是,埋入一个延时消息(延时炸弹)。那么埋入了延时炸弹干什么呢?当然是为了能够在有效时间内解除这个炸弹咯。如果这个炸弹最终在延时时间内没有被移除,则Handler最终被dispatch到该消息的时候,不就触发了Anr了吗。这就是我们Anr的一个整体猜想。下面咱就验证一下这个想法吧。

在AS中的scheduleCreateService()方法,执行了bumpServiceExecutingLocked()之后,调用了app.thread.scheduleCreateService()这句话,跨进程调用到了发起startService这个进程中的ApplicationThread类,它是ActivityThread的内部类,通过Binder机制负责跨进程通信。下面是该类执行scheduleCreateService()的内容:

//ApplicationThread 代码:
public final void scheduleCreateService(IBinder token,
                ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
            updateProcessState(processState, false);
            CreateServiceData s = new CreateServiceData();
            s.token = token;
            s.info = info;
            s.compatInfo = compatInfo;

            sendMessage(H.CREATE_SERVICE, s);
        }
        
        
//ActivityThread代码:
private void sendMessage(int what, Object obj, int arg1, int arg2, boolean async) {
        if (DEBUG_MESSAGES) Slog.v(
            TAG, "SCHEDULE " + what + " " + mH.codeToString(what)
            + ": " + arg1 + " / " + obj);
        Message msg = Message.obtain();
        msg.what = what;
        msg.obj = obj;
        msg.arg1 = arg1;
        msg.arg2 = arg2;
        if (async) {
            msg.setAsynchronous(true);
        }
        mH.sendMessage(msg);//类H,继承Handler,专门接收AMS调度过来的四大组件调度消息。
    }
    
//H代码:
public void handleMessage(Message msg) {
	switch (msg.what) {
    	。。。//省略
    	 case CREATE_SERVICE:
                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, ("serviceCreate: " + String.valueOf(msg.obj)));
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
		。。。//省略
    }
}

//ActivityThread代码:
private void handleCreateService(CreateServiceData data) {
        ...//省略

        try {
            if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);

            ContextImpl context = ContextImpl.createAppContext(this, packageInfo);
            context.setOuterContext(service);

            Application app = packageInfo.makeApplication(false, mInstrumentation);
            service.attach(context, this, data.info.name, data.token, app,
                    ActivityManager.getService());
            service.onCreate();//调用onCreate()
            mServices.put(data.token, service);
            try {//跨进程传达service创建成功。
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(service, e)) {
                throw new RuntimeException(
                    "Unable to create service " + data.info.name
                    + ": " + e.toString(), e);
            }
        }
    }
复制代码

由上面的核心代码片段可以看出,最终Service的创建流程会由sys_server进程中的AMS,跨进程调用ApplicationThread,在App进程通过Handler发送消息的形式,执行handleCreateService(),调用Service.onCreate()后,再跨进程通知AMSserviceDoneExecuting()。走到这里,Service在App进程就创建完毕了。onCreate()执行完成。

这一步的流程中,埋下的炸弹时间也在悄然流逝。我们继续往下看,接下来就看AMS中如何处理炸弹了。

AMS被调用到了serviceDoneExecuting() 方法后,会调用AS的serviceDoneExecutingLocked()。 在处理了Service.START_STICKY等各种乱七八糟的标记位之后,走到serviceDoneExecutingLocked()方法,这里真正执行到了“拆除炸弹"的过程,将此前埋入的延时消息remove。

private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing) {
		//省略...
        r.executeNesting--;
        if (r.executeNesting <= 0) {
            if (r.app != null) {
                if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                        "Nesting at 0 of " + r.shortName);
                r.app.execServicesFg = false;
                r.app.executingServices.remove(r);
                if (r.app.executingServices.size() == 0) {
                    if (DEBUG_SERVICE || DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING,
                            "No more executingServices of " + r.shortName);
                   //拆除炸弹!!!
       mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                } else if (r.executeFg) {
                    // Need to re-evaluate whether the app still needs to be in the foreground.
                    for (int i=r.app.executingServices.size()-1; i>=0; i--) {
                        if (r.app.executingServices.valueAt(i).executeFg) {
                            r.app.execServicesFg = true;
                            break;
                        }
                    }
                }
                if (inDestroying) {
                    if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
                            "doneExecuting remove destroying " + r);
                    mDestroyingServices.remove(r);
                    r.bindings.clear();
                }
                mAm.updateOomAdjLocked(r.app, true);
            }
            r.executeFg = false;
            if (r.tracker != null) {
                r.tracker.setExecuting(false, mAm.mProcessStats.getMemFactorLocked(),
                        SystemClock.uptimeMillis());
                if (finishing) {
                    r.tracker.clearCurrentOwner(r, false);
                    r.tracker = null;
                }
            }
            if (finishing) {
                if (r.app != null && !r.app.persistent) {
                    r.app.services.remove(r);
                    if (r.whitelistManager) {
                        updateWhitelistManagerLocked(r.app);
                    }
                }
                r.app = null;
            }
        }
    }
复制代码

那么问题来了,如果在调用mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);的时候发现没有该消息了会发生什么呢? 那其实就说明,mAm.mHandler 已经处理了该消息。我们进入到mAm.mHandler中去一探究竟,它收到该消息会做什么事情。

final class MainHandler extends Handler {
            public MainHandler(Looper looper) {
                super(looper, null, true);
            }
    
            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                //...省略
                case SERVICE_TIMEOUT_MSG: {
                mServices.serviceTimeout((ProcessRecord)msg.obj);
            } break;
				//...省略
            }
            //...省略
           }
           //...省略
复制代码

它委托了AS去执行serviceTimeout(),

    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;
            } else {
                Message msg = mAm.mHandler.obtainMessage(
                        ActivityManagerService.SERVICE_TIMEOUT_MSG);
                msg.obj = proc;
                mAm.mHandler.sendMessageAtTime(msg, proc.execServicesFg
                        ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
            }
        }

        if (anrMessage != null) {
            mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
        }
    }
复制代码

这个方法的前半部分在手机Anr信息,最后一句则是引爆Anr炸弹的直接执行者。走到这里,Service在创建过程中的Anr监控流程就分析完了。

再来回顾开篇咱提到的三个问题也就迎刃而解了。

  1. Service 的 Anr监控机制都由那些重量级角色参与 答:对Service而言,Anr监控流程中涉及到了App进程和Sys_Server进程的通信。基于执行顺序,参与的累有:ContextImpl、ActivityManagerService、ActiveServices、ApplicationThread和ActivityThread,还用到了各自进程中的Handler机制。

  2. Service 的 Anr监控机制的建立流程是怎样的 答:在onCreate的调用流程中,Anr机制的流程可以用一下流程图表示:

  3. Service 的 Anr监控机制的实现原理是什么

    答:Anr监控的实现原理,是基于Handler消息机制发送延时消息,以不同的Anr超时时间作为延时消息的延时时间。若在该时间内执行完毕,则remove该延时消息;否则会触发该延时消息,执行Anr的上报流程。

免责声明:文章版权归原作者所有,其内容与观点不代表Unitimes立场,亦不构成任何投资意见或建议。

android

474

相关文章推荐

未登录头像

暂无评论