个人博客
http://www.milovetingting.cn
Android中ANR的触发机制-Service篇 概述 ANR,即Application Not Responding,应用程序不响应。在Android系统中,对于事件的处理,都需要在一定的时间内完成,如果处理超时的话,就会触发ANR,弹出不响应的界面,让用户选择等待或是立即结束应用。ANR机制的简单流程:在事件发给应用处理前,会先发一个延时消息到系统的Looper中,如果应用在规定的时间内执行完成,则会移除掉延时消息。如果没有在规定时间内执行完,就会在处理延时消息中,触发ANR。
ANR主要场景:
Service
BroadcastReceiver
ContentProvider
Input:包括输入和触摸
触发机制分析 下面对Service进行源码分析,源码为Android9.0。
首先从Service的启动来分析。这里只分析startService的模式,bindService模式暂时不分析。
附一张时序图
不管是通过Activity的startService还是非Activity的Context中的startService,最终都是调用ContextWrapper的startService方法:
1 2 3 4 5 @Override public ComponentName startService (Intent service) { return mBase.startService(service); }
mBase对应的具体Context类为ContextImpl。ContextImpl的startService方法:
1 2 3 4 5 6 @Override public ComponentName startService (Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, false , mUser); }
startService方法调用startServiceCommon方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 private ComponentName startServiceCommon (Intent service, boolean requireForeground, UserHandle user) { try { validateServiceIntent(service); service.prepareToLeaveProcess(this ); ComponentName cn = ActivityManager.getService().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), requireForeground, getOpPackageName(), user.getIdentifier()); if (cn != null ) { if (cn.getPackageName().equals("!" )) { throw new SecurityException ( "Not allowed to start service " + service + " without permission " + cn.getClassName()); } else if (cn.getPackageName().equals("!!" )) { throw new SecurityException ( "Unable to start service " + service + ": " + cn.getClassName()); } else if (cn.getPackageName().equals("?" )) { throw new IllegalStateException ( "Not allowed to start service " + service + ": " + cn.getClassName()); } } return cn; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
在这个方法里,跨进程调用AMS的startService方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 @Override public ComponentName startService (IApplicationThread caller, Intent service, String resolvedType, boolean requireForeground, String callingPackage, int userId) throws TransactionTooLargeException { enforceNotIsolatedCaller("startService" ); if (service != null && service.hasFileDescriptors() == true ) { throw new IllegalArgumentException ("File descriptors passed in Intent" ); } if (callingPackage == null ) { throw new IllegalArgumentException ("callingPackage cannot be null" ); } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground); synchronized (this ) { final int callingPid = Binder.getCallingPid(); final int callingUid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); ComponentName res; try { res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, requireForeground, callingPackage, userId); } finally { Binder.restoreCallingIdentity(origId); } return res; } }
AMS中调用ActiveServices的startServiceLocked方法:
1 2 3 4 5 6 7 8 ComponentName startServiceLocked (IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId) throws TransactionTooLargeException { ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting); return cmp; }
这个方法又调用了startServiceInnerLocked方法:
1 2 3 4 5 6 7 8 9 10 ComponentName startServiceInnerLocked (ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException { String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false , false ); if (error != null ) { return new ComponentName ("!!" , error); } }
这个方法调用bringUpServiceLocked方法:
1 2 3 4 5 6 7 8 private String bringUpServiceLocked (ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException { realStartServiceLocked(r, app, execInFg); }
这个方法里调用realStartServiceLocked方法:
1 2 3 4 5 6 7 8 9 10 11 private final void realStartServiceLocked (ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { bumpServiceExecutingLocked(r, execInFg, "create" ); app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); }
这里先调用了bumpServiceExecutingLocked方法用来设置超时消息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 private final void bumpServiceExecutingLocked (ServiceRecord r, boolean fg, String why) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, ">>> EXECUTING " + why + " of " + r + " in app " + r.app); else if (DEBUG_SERVICE_EXECUTING) Slog.v(TAG_SERVICE_EXECUTING, ">>> EXECUTING " + why + " of " + r.shortName); boolean timeoutNeeded = true ; if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) && (r.app != null ) && (r.app.pid == android.os.Process.myPid())) { Slog.w(TAG, "Too early to start/bind service in system_server: Phase=" + mAm.mBootPhase + " " + r.getComponentName()); timeoutNeeded = false ; } 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 (timeoutNeeded && r.app.executingServices.size() == 1 ) { scheduleServiceTimeoutLocked(r.app); } } } else if (r.app != null && fg && !r.app.execServicesFg) { r.app.execServicesFg = true ; if (timeoutNeeded) { scheduleServiceTimeoutLocked(r.app); } } r.executeFg |= fg; r.executeNesting++; r.executingStart = now; }
这个方法中调用scheduleServiceTimeoutLocked方法:
1 2 3 4 5 6 7 8 9 10 11 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); }
调用ActivityManagerService的MainHandler发送一个SERVICE_TIMEOUT消息,这里具体根据是否为前台消息发送的消息不同。
前台服务超时时间:20s,后台服务超时时间:200s
1 2 3 4 5 static final int SERVICE_TIMEOUT = 20 *1000 ; static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10 ;
设置超时消息就先看到这里,接着看启动Service
调用ProcessRecord中的IApplicationThread类型的thread属性的scheduleCreateService方法,即调用到了ActivityThread的内部类ApplicationThread的scheduleCreateService方法:
1 2 3 4 5 6 7 8 9 10 11 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的sendMessage方法:
1 2 3 4 void sendMessage (int what, Object obj) { sendMessage(what, obj, 0 , 0 , false ); }
最终通过Handler发送了一个消息出去
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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); }
在mH的handleMessage中回调处理:
1 2 3 4 5 6 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 ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 private void handleCreateService (CreateServiceData data) { unscheduleGcIdler(); LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null ; try { java.lang.ClassLoader cl = packageInfo.getClassLoader(); service = packageInfo.getAppFactory() .instantiateService(cl, data.info.name, data.intent); } catch (Exception e) { if (!mInstrumentation.onException(service, e)) { throw new RuntimeException ( "Unable to instantiate service " + data.info.name + ": " + e.toString(), 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, ActivityManager.getService()); service.onCreate(); mServices.put(data.token, service); try { 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); } } }
如果在规定的时间内完成处理,则会调用AMS的serviceDoneExecuting:
1 2 3 4 5 6 7 8 9 10 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); } }
这个方法调用ActiveServices中的serviceDoneExecutingLocked方法:
1 2 3 4 5 6 void serviceDoneExecutingLocked (ServiceRecord r, int type, int startId, int res) { serviceDoneExecutingLocked(r, inDestroying, inDestroying); }
这个方法会调用另一个重载方法:
1 2 3 4 5 6 7 private void serviceDoneExecutingLocked (ServiceRecord r, boolean inDestroying, boolean finishing) { mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app); }
在这个方法里移除了前面的延时消息,就不会触发ANR。
如果没有及时移除这个消息,那么将会在ActivityManagerService的MainHandler中触发:
MainHandler收到消息的处理:
1 2 3 4 5 6 7 8 9 10 11 @Override public void handleMessage (Message msg) { switch (msg.what) { case SERVICE_TIMEOUT_MSG: { mServices.serviceTimeout((ProcessRecord)msg.obj); } break ; } }
这个方法调用ActiveServices中的serviceTimeout方法:
1 2 3 4 5 6 void serviceTimeout (ProcessRecord proc) { if (anrMessage != null ) { mAm.mAppErrors.appNotResponding(proc, null , null , false , anrMessage); } }
在这里弹出了不响应的界面。