Android中ANR的触发机制-Service篇

Android中ANR的触发机制-Service篇 概述

ANR,即Application Not Responding,应用程序不响应。在Android系统中,对于事件的处理,都需要在一定的时间内完成,如果处理超时的话,就会触发ANR,弹出不响应的界面,让用户选择等待或是立即结束应用。ANR机制的简单流程:在事件发给应用处理前,会先发一个延时消息到系统的Looper中,如果应用在规定的时间内执行完成,则会移除掉延时消息。如果没有在规定时间内执行完,就会在处理延时消息中,触发ANR。

ANR主要场景:

Service

BroadcastReceiver

ContentProvider

Input:包括输入和触摸

触发机制分析

下面对Service进行源码分析,源码为Android9.0。

首先从Service的启动来分析。这里只分析startService的模式,bindService模式暂时不分析。

附一张时序图

Service的ANR机制

不管是通过Activity的startService还是非Activity的Context中的startService,最终都是调用ContextWrapper的startService方法:

//ContextWrapper @Override public ComponentName startService(Intent service) { return mBase.startService(service); }

mBase对应的具体Context类为ContextImpl。ContextImpl的startService方法:

//ContextImpl @Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, false, mUser); }

startService方法调用startServiceCommon方法

//ContextImpl 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方法

//AMS @Override public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, boolean requireForeground, String callingPackage, int userId) throws TransactionTooLargeException { enforceNotIsolatedCaller("startService"); // Refuse possible leaked file descriptors 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 { //调用ActiveServices的startServiceLocked方法 res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, requireForeground, callingPackage, userId); } finally { Binder.restoreCallingIdentity(origId); } return res; } }

AMS中调用ActiveServices的startServiceLocked方法:

//ActiveServices 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方法:

//ActiveServices 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方法:

//ActiveServices private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException { //... realStartServiceLocked(r, app, execInFg); //... }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgggzd.html