Android Framework ANR - Service

154 阅读2分钟

image.png

谷歌对ANR的解释和排查方案

startService 的基础流程


ContextImpl.java


startService()-->startServiceCommon()

ComponentName cn = ActivityManager.getService().startService(
                    mMainThread.getApplicationThread(), service,
                    service.resolveTypeIfNeeded(getContentResolver()), requireForeground,
                    getOpPackageName(), getAttributionTag(), user.getIdentifier());




 //调用到AMS的 startService

final ActiveServices mServices;

 
 res = mServices.startServiceLocked(caller, service,
                        resolvedType, callingPid, callingUid,
                        requireForeground, callingPackage, callingFeatureId, userId);  
                                               
        

进入ActiveServices ,该类是AMS 中 负责处理服务启动 /绑定/停止等功能的管件类

       
//方法基本流程  
startServiceLocked()
//-->
startServiceInnerLocked()
//-->
bringUpServiceLocked()
//-->
realStartServiceLocked(){

bumpServiceExecutingLocked(){

//发送ANR延时消息
   scheduleServiceTimeoutLocked(r.app);
   }

//启动服务
   thread.scheduleCreateService()


 } 

核心方法

  • 先看下scheduleServiceTimeoutLocked() 方法
//ActiveServices .java
 final ActivityManagerService mAm;
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
    if (proc.mServices.numberOfExecutingServices() == 0 || proc.getThread() == null) {
        return;
    }
    Message msg = mAm.mHandler.obtainMessage(
            ActivityManagerService.SERVICE_TIMEOUT_MSG);
    msg.obj = proc;
    mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
            ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}

该方法会调用AMSmHandler

 case SERVICE_TIMEOUT_MSG: {
                mServices.serviceTimeout((ProcessRecord) msg.obj);
            } break;

mServices.serviceTimeout((ProcessRecord) msg.obj);

  // How long we wait for a service to finish executing.
    static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;

    // How long we wait for a service to finish executing.
    static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;

  void serviceTimeout(ProcessRecord proc) {
        String anrMessage = null;
        synchronized(mAm) {
            if (proc.isDebugging()) {
                // The app's being debugged, ignore timeout.
                return;
            }
            final ProcessServiceRecord psr = proc.mServices;
            if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null) {
                return;
            }
            final long now = SystemClock.uptimeMillis();
            final long maxTime =  now -
                    (psr.shouldExecServicesFg() ? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
            ServiceRecord timeout = null;
            long nextTime = 0;
            for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
                ServiceRecord sr = psr.getExecutingServiceAt(i);
                if (sr.executingStart < maxTime) {
                    timeout = sr;
                    break;
                }
                if (sr.executingStart > nextTime) {
                    nextTime = sr.executingStart;
                }
            }
            if (timeout != null && mAm.mProcessList.isInLruListLOSP(proc)) {
             
                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.shortInstanceName;
            } else {
                Message msg = mAm.mHandler.obtainMessage(
                        ActivityManagerService.SERVICE_TIMEOUT_MSG);
                msg.obj = proc;
                mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg()
                        ? (nextTime+SERVICE_TIMEOUT) : (nextTime + SERVICE_BACKGROUND_TIMEOUT));
            }
        }

        if (anrMessage != null) {
            mAm.mAnrHelper.appNotResponding(proc, anrMessage);
        }
    }

这里这里其实核心就是计算是否超时,如果超时,则调用AnrHelper进行对应处理,没有则发送handler消息继续等待。 这里可以看到默认是20S,后台服务进行了*10

  • 再看下 thread.scheduleCreateService()

这里的thread是 IApplicationThread ,其实就是ActivityThread 里的 ApplicationThreadAMS通过他和APP进行交互。

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);
}

//
case CREATE_SERVICE:
                    if (Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
                        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                                ("serviceCreate: " + String.valueOf(msg.obj)));
                    }
                    handleCreateService((CreateServiceData)msg.obj);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                    break;
                    
                    
                    
  handleCreateService(){
//省略

try {
                ActivityManager.getService().serviceDoneExecuting(
                        data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
                    }                   

这里看到又回到了AMS

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, false);
        }
    }

这里再次进ActiveServices,在serviceDoneExecutingLocked() 进行了消息的移除。

serviceDoneExecutingLocked(){
  //省略
    mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}

在之前基础代码流程,调用 bumpServiceExecutingLocked() 方法,然后在该方法里调用scheduleServiceTimeoutLocked()。可以看到该方法在服务绑定解绑启动等都进行了消息发送,也就是如果在这些阶段发生了超时,则就会显示ANR

image.png

总结:

其实在Service 里,启动或者绑定解绑等状态,调用AMSmHandler 发送了延迟消息,如果在对应阶段没有对该消息进行移除,倒计时结束就进行了ANR的显示和处理。