ANR源码分析之Service Timeout
来源:互联网 发布:java wait await 区别 编辑:程序博客网 时间:2024/05/08 20:18
在前面的一篇文章中,分析了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。
阅读全文
0 0
- ANR源码分析之Service Timeout
- ANR源码分析之InputDispatcher Timeout
- ANR源码分析之Broadcast Timeout
- ANR源码分析之ContentProviderClient Timeout
- android ANR源码分析 --- 之二
- android ANR源码分析 --- 之三
- android ANR源码分析 --- 之四
- 16-service之$timeout
- android-ANR源码分析
- Android 源码分析ANR
- Android ANR源码原理分析
- android ANR源码分析 --- 之一
- Android ANR-Keydispatch timeout
- Android ANR-Broadcast Timeout
- Android Service之MountService源码分析
- MQTT Paho之Android service源码分析
- Android Service之MountService源码分析
- Hadoop Common源码分析之服务Service
- 《大话数据结构》读书笔记(2)
- SpringCloud概念
- 服务器与客户端回叫
- 18 WebGL使用varying变量从顶点着色器向片元着色器传值
- com.commonsware.cwac.camera的配置
- ANR源码分析之Service Timeout
- 关闭445端口
- 【CSS编码规范】
- 杭州
- C++ Prime 之 类类型转换初步学习
- Articulate Studio 13 Pro 4.8课件制作中文汉化破解版安装教程(附下载)
- 《UNIX网络编程 卷1》 笔记: 错误处理和包裹函数
- NAT(网络地址转换)技术与代理服务器原理
- 爬坑总结———elementary OS 0.4.1 Loki 下引导修复和安装搜狗输入法