添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
爱搭讪的猴子  ·  Spring ...·  1 年前    · 

在前面的一篇文章中,分析了 Broadcast Timeout 的流程,接下来继续分析Service Timeout的流程。Service默认不会运行在子线程中,它也不会运行在一个独立的进程中,它同样执行在UI线程中,因此也不能在Service中执行耗时操作,否则也会产生的ANR。

Service Timeout整体流程如下图所示:

1.startService(ContextImpl.java)

* 启动服务 public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, mUser); private ComponentName startServiceCommon(Intent service, UserHandle user) { try { validateServiceIntent(service);//验证Service的Intent service.prepareToLeaveProcess(this); ComponentName cn = ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), getOpPackageName(), user.getIdentifier());//调用AMS的start方法 ........ return cn; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); 2.startService(ActivityManagerService.java)
在ActivityManagerService.java类中
 public ComponentName startService(IApplicationThread caller, Intent service,
            String resolvedType, String callingPackage, int userId)
            throws TransactionTooLargeException {
        enforceNotIsolatedCaller("startService");
        ......
        synchronized(this) {
            final int callingPid = Binder.getCallingPid();
            final int callingUid = Binder.getCallingUid();
            final long origId = Binder.clearCallingIdentity();
            ComponentName res = mServices.startServiceLocked(caller, service,
                    resolvedType, callingPid, callingUid, callingPackage, userId);//调用ActiveServices的startServiceLocked方法
            Binder.restoreCallingIdentity(origId);
            return res;
3.startServiceLocked(ActiveServices.java) 

    在ActiveServices.java类中
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
            int callingPid, int callingUid, String callingPackage, final int userId)
            throws TransactionTooLargeException {
        final boolean callerFg;
        if (caller != null) {
         final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller);
         .........
         //调用者不是处于后台线程组中
         callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
       } else {
          callerFg = true;
     .......
        ServiceRecord r = res.record;
        ......
        //准备startService参数
        r.lastActivity = SystemClock.uptimeMillis();
        r.startRequested = true;
        r.delayedStop = false;
        r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(),
                service, neededGrants));
        ......
        return startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
    ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
        ServiceState stracker = r.getTracker();
        if (stracker != null) {
            stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
        r.callStart = false;
        synchronized (r.stats.getBatteryStats()) {
            r.stats.startRunningLocked();
        //调用bringUpServiceLocked方法将服务调起
        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
        .......
        return r.name;
    private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
            boolean whileRestarting, boolean permissionsReviewRequired)
            throws TransactionTooLargeException {
         ......
        final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0;
        ......
        if (!isolated) {
            app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false);
            if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
                        + " app=" + app);
            if (app != null && app.thread != null) {
                try {
                    app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats);
                    //调用realStartServiceLocked方法启动服务
                    realStartServiceLocked(r, app, execInFg);
                    return null;
                } catch (TransactionTooLargeException e) {
                    throw e;
                } catch (RemoteException e) {
                    Slog.w(TAG, "Exception when starting service " + r.shortName, e);
        } else {
           ........
        ........
    private final void realStartServiceLocked(ServiceRecord r,
            ProcessRecord app, boolean execInFg) throws RemoteException {
        .......
        r.app = app;
        r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
        final boolean newService = app.services.add(r);
        //开始监控onCreate方法执行时长
        bumpServiceExecutingLocked(r, execInFg, "create");
        mAm.updateLruProcessLocked(app, false, null);
        mAm.updateOomAdjLocked();
        boolean created = false;
        try {
            ......
            mAm.notifyPackageUse(r.serviceInfo.packageName,
                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
            app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
           //开始Service的onCreate流程
            app.thread.scheduleCreateService(r, r.serviceInfo,
                    mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
                    app.repProcState);
            r.postNotification();
            created = true;
        } catch (DeadObjectException e) {
           ......
        } finally {
            ......
        ......
        //开始Service的onBind流程
        requestServiceBindingsLocked(r, execInFg);
        ......
       //开始Service的onStart流程
        sendServiceArgsLocked(r, execInFg, true);
        ......
 4.bumpServiceExecutingLocked(ActiveServices.java) 
    * 记录服务方法执行开始时间,并开始监控服务方法执行是否超时
    private final void bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why) {
        ......
        long now = SystemClock.uptimeMillis();//记录当前方法执行的开始时间
        if (r.executeNesting == 0) {
            r.executeFg = fg;
            ServiceState stracker = r.getTracker();
            if (stracker != null) {
                stracker.setExecuting(true, mAm.mProcessStats.getMemFactorLocked(), now);
            if (r.app != null) {
                r.app.executingServices.add(r);
                r.app.execServicesFg |= fg;
                if (r.app.executingServices.size() == 1) {
                    //服务方法首次执行时,调用该方法
                    scheduleServiceTimeoutLocked(r.app);
        } else if (r.app != null && fg && !r.app.execServicesFg) {
            r.app.execServicesFg = true;
            //服务方法非首次执行时,调用该方法
            scheduleServiceTimeoutLocked(r.app);
        r.executeFg |= fg;//记录服务是否在前台执行
        r.executeNesting++;//记录服务执行方法的次数
        r.executingStart = now;//记录服务方法执行的开始时间
    }
    在执行服务的生命周期方法时,会调用bumpServiceExecutingLocked来监控服务方法执行是否超时,该方法最终调用scheduleServiceTimeoutLocked方法来发送SERVICE_TIMEOUT_MSG消息到ActivityManagerService中。
 void scheduleServiceTimeoutLocked(ProcessRecord proc) {
        ......
        long now = SystemClock.uptimeMillis();
        Message msg = mAm.mHandler.obtainMessage(
                ActivityManagerService.SERVICE_TIMEOUT_MSG);
        msg.obj = proc;
        //发送消息到AMS中,并添加延迟时间,如果是前台服务,则超时时间为20s,如果是后台服务,则超时时间为200s
        mAm.mHandler.sendMessageAtTime(msg,
                proc.execServicesFg ? (now+SERVICE_TIMEOUT) : (now+ SERVICE_BACKGROUND_TIMEOUT));
     //服务超时时间为20s
    static final int SERVICE_TIMEOUT = 20*1000;
    //在后台线程组中服务超时时间为200s
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
5.handleMessage方法(ActivityManagerService.java)
    ActivityManagerService接收到scheduleServiceTimeoutLocked方法发送过来的SERVICE_TIMEOUT_MSG消息后,调用ActiveServices的serviceTimeout方法发送ANR消息
 public void handleMessage(Message msg) {
         case SERVICE_TIMEOUT_MSG: {
                ......
                mServices.serviceTimeout((ProcessRecord)msg.obj);//调用ActiveServices的serviceTimeOut()方法
            } break;
6.serviceTimeout方法(ActiveServices.java) 
void serviceTimeout(ProcessRecord proc) {
        String anrMessage = null;
        synchronized(mAm) {
            ......
            final long now = SystemClock.uptimeMillis();
            //计算当前时间减去服务超时时间
            final long maxTime =  now -
                    (proc.execServicesFg ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
            ServiceRecord timeout = null;
            long nextTime = 0;
            //遍历服务执行方法列表,如果有方法执行时间超过服务执行超时最大时间,则发送ANR消息
            for (int i=proc.executingServices.size()-1; i>=0; i--) {
                ServiceRecord sr = proc.executingServices.valueAt(i);
                //服务执行开始时间小于maxTime,则说明服务已经超时了
                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);
                ......
                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));
        //服务超时,发送ANR消息给AppErrors给用户显示
        if (anrMessage != null) {
            mAm.mAppErrors.appNotResponding(proc, null, null, false, anrMessage);
    }
    在serviceTimeout方法中判断服务方法执行是否超时,如果执行超时则发送ANR消息给AppErrors,否则继续监控下一个服务方法执行是否超时。

    在服务方法执行完成后,将取消服务超时监控。在realStartServiceLocked方法中,执行完bumpServiceExecutingLocked方法后,接着执行ActivityThread的scheduleCreateService方法。
1.scheduleCreateService方法(ActivityThread.java)

* createService方法来创建服务 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); public void handleMessage(Message msg) { 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; private void handleCreateService(CreateServiceData data) { ..... // 获取服务的package信息 LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; try { // 通过反射创建服务类 java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = (Service) cl.loadClass(data.info.name).newInstance(); } catch (Exception e) { ...... 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, ActivityManagerNative.getDefault()); //回调服务的onCreate方法 service.onCreate(); mServices.put(data.token, service); try { ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);//调用AMS的serviceDoneExecuting方法 } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (Exception e) { ...... 2.serviceDoneExecuting方法(ActivityManagerService.java)
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
        synchronized(this) {
            if (!(token instanceof ServiceRecord)) {
                Slog.e(TAG, "serviceDoneExecuting: Invalid service token=" + token);
                throw new IllegalArgumentException("Invalid service token");
            mServices.serviceDoneExecutingLocked((ServiceRecord)token, type, startId, res);
3.serviceDoneExecutingLocked方法(ActiveServices.java) 
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res) {
        boolean inDestroying = mDestroyingServices.contains(r);
        if (r != null) {
            .......
            final long origId = Binder.clearCallingIdentity();
            serviceDoneExecutingLocked(r, inDestroying, inDestroying);
            Binder.restoreCallingIdentity(origId);
        } else {
            ........
    private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
            boolean finishing) {
        ......
        r.executeNesting--;
        if (r.executeNesting <= 0) {
            if (r.app != null) {
                .....
                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);
                    //移除SERVICE_TIMEOUT_MSG消息,取消对服务方法执行时间的监控
                    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
                } else if (r.executeFg) {
                   ......
                .......
            r.executeFg = false;
            .......
    }
    在serviceDoneExecutingLocked方法中,如果执行完了服务的方法,就移除SERVICE_TIMEOUT_MSG消息,取消对服务方法执行时间的监控。

    至此,完整的介绍了在执行服务方法的时候,设置监听服务超时的过程以及移除监听服务超时的过程。默认情况下,服务执行的超时时间为20s,在后台线程组中服务执行超时时间为200s。

在前面的一篇文章中,分析了Broadcast Timeout的流程,接下来继续分析Service Timeout的流程。Service默认不会运行在子线程中,它也不会运行在一个独立的进程中,它同样执行在UI线程中,因此也不能在Service中执行耗时操作,否则也会产生的ANR。Service Timeout整体流程如下图所示:1.startService(ContextIm
ANR service TimeOut 超时判断Service超时判断Service启动设置Handler超时消息AMS.MainHandler超时响应SERVICE_TIMEOUT_MSGActiveServices.serviceTimeoutAppErrors.appNotResponding输出Log何时清除超时消息SERVICE_TIMEOUT_MSG感谢 android-9.0.0_...
前言:之前在(六十四)Android O Service启动流程梳理——startService 梳理了startService的一般流程,anr的没有涉及,本篇就以anr的为关注点梳理下流程。 1. ANR源码分析Service Timeout 2.(六十四)Android O Service启动流程梳理——startService 1. service anr关键方法
Timeout 时间已到。在操作完成之前超时时间已过或服务器未响应解决方案 1.最近调用webservice时总是提示timeout失败参考网上变更timeout的时间并没有起作用 <system.serviceModel>
ANR概念 ANR(Application Not Responding) 应用程序无响应。如果应用程序在UI线程被阻塞太长时间,就会出现ANR,通常出现ANR,系统会弹出一个提示提示框,让用户知道,该程序正在被阻塞,是否继续等待还是关闭。 出现ANR必须解决 ANR类型 为什么出现ANR 1:主线程频繁进行耗时的IO操作:如数据库读写 2:多线程操作的死锁,主线程被block;held by 3:主线程被Binder 对端block; 4:System Server中WatchDog出现ANRANR(Application Not responding),是指应用程序未响应,Android系统对于一些事件需要在一定的时间范围内完成,如果超过预定时间能未能得到有效响应或者响应时间过长,都会造成ANR。一般地,这时往往会弹出一个提示框,告知用户当前xxx未响应,用户可选择继续等待或者Force Close,并不是所有的ANR都会有提示框,文字后面会给出答案 那么哪些场景会造成ANR呢? Service Timeout:比如前台服务在20s内未执行完成,后台60s未完成;...
首次开机出现黑屏问题后我们首先排查最近的提交,发现(Change-Id: Iafe992f5f83527d6d590536d315f8110c55296d8)最有可能导致此问题,回退该修改后编译版本发现可正常开机,确认是该修改导致。具体分析该修改为什么会导致首次开机4-5分钟黑屏后才会进入开机向导的问题。 1.先看(Change-Id: Iafe992f5f83527d6d590536d31
1、web.config配置,<system.web></system.web>里面增加:<httpRuntime maxRequestLength="10240" appRequestQueueLimit="100" useFullyQualifiedRedirectUrl="true" executionTimeout="1200" /> 2、扩...
现在感觉自己做的工作,基本上脱离Android了就是用java写代码,而且可能试用期完了就会被刷,很多东西是公司自己的,完全不知道怎么下手研究,导师指导也就是几句话的说你看下哪里哪里的代码。要不是旁边的一个大牛,我是真的走不下去了。大佬们,要是被刷求介绍工作,不怕加班,只怕没有讨论没有指导。 写这篇博客另外感谢之前小米的同事,她在北邮念完研究生,但是却很低调,她是很好的学姐,她当时工作就...
ANR(应用程序无响应)是一种常见的 Android 系统问题,表示应用程序长时间没有响应。这通常是由于应用程序的某些代码卡住了导致的。 如果 ANR 发生在 Binder 上,这意味着应用程序正在等待 Binder 进程完成某些操作。Binder 是 Android 系统的一种机制,用于在不同的进程间进行进程间通信(IPC)。如果 Binder 进程被锁住,则应用程序就无法继续执行,并出现 ANR。 解决 ANR 问题的一种方法是使用 Android Studio 的「ANR 分析器」工具来分析应用程序的堆栈跟踪信息,以确定造成 ANR 的原因。通常可以通过优化应用程序的代码或更改应用程序的设计来解决 ANR 问题。