在前面文章我们分析了四大组件中的两个:Broadcast和Activity,这章我们分析四大组件中的服务(Service)的启动过程。Service的启动方式有两种:一种是startService,一种是bindService;第一种通常是开启一个服务执行后台任务,不进行通信,第二章通过是启动服务进行通信。下面我们就根据这两种启动方式来讲Service的启动流程以及unbindService和stopService流程。
Service启动流程-startService
首先来看启动流程时序图:
Service1.jpg
Step0.ContextImpl.startService
@Override public ComponentName startService(Intent service) { warnIfCallingFromSystemProcess(); return startServiceCommon(service, mUser); } |
调用当前类中的startServiceCommon方法。
Step1.ContextImpl.startServiceCommon
private ComponentName startServiceCommon(Intent service, UserHandle user) { try { // 检验Intent,组件和包名不能为空 validateServiceIntent(service); service.prepareToLeaveProcess(this); // 通过getDefault方法获取AMS的一个代理对象(ActivityManagerProxy),然后调用这个代理对象 // 的startService方法来请求AMS启动Service ComponentName cn = ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded( getContentResolver()), getOpPackageName(), user.getIdentifier()); ... return cn; } catch (RemoteException e) { ... } } |
首先验证Intent中传递的组件名是否为空,为什么判断下面我们介绍,接着通过代理对象ActivityManagerProxy,通过Binder调用AMS(ActivityManagerService)中的对应方法startService。我们先看包名验证。
Step2.ContextImpl.validateServiceIntent
private void validateServiceIntent(Intent service) { if (service.getComponent() == null && service.getPackage() == null) { if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) { IllegalArgumentException ex = new IllegalArgumentException( "Service Intent must be explicit: " + service); throw ex; } else { Log.w(TAG, "Implicit intents with startService are not safe: " + service + " " + Debug.getCallers(2, 3)); } } } |
这里给出了如果系统在Android5.0及以上版本,启动服务必须为显式启动,否则抛出异常,这个情况我们在刚开始在高于5.0系统都会遇到过,限制就在这里,所以,5.0及以上系统必须用显式的方式启动服务。
3.AMP.startService
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) throws RemoteException { ... // 通过Binder对象mRemote向AMS发送一个类型为START_SERVICE_TRANSACTION的进程间通信请求, // 然后会调用AMS中的对应的startService方法 mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0); ... return res; } |
看过前面文章的对这一段代码应该很熟悉了,这个就是通过Binder调用AMS中对应方法的。所以我们直接看AMS。
4.AMS.startService
public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) throws TransactionTooLargeException { ... synchronized (this) { ... ComponentName res = mServices.startServiceLocked(caller, service, resolvedType, callingPid, callingUid, callingPackage, userId); Binder.restoreCallingIdentity(origId); return res; } } |
这里的mServices是ActiveServices,因此调用的是ActiveServices中的startServiceLocked方法。
5.ActiveServices.startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType, int callingPid, int callingUid, String callingPackage, final int userId) throws TransactionTooLargeException { ... // 解析service这个Intent,就是解析在AndroidManifest.xml定义的Service标签的intent-filter相关内容 // 并将其内容保存在Service的record(ServiceRecord)中 ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, callingPid, callingUid, userId, true, callerFg, false); ... // 每一个Service组件都使用一个ServiceRecord对象来描述,就像每一个Activity都是用一个ActivityRecord // 对象来描述一样 ServiceRecord r = res.record; ... // 加入启动服务列表 r.pendingStarts.add(new ServiceRecord.StartItem(r, false, r.makeNextStartId(), service, neededGrants)); final ServiceMap smap = getServiceMap(r.userId); boolean addToStarting = false; // 如果是非前台(后台)进程调用 if (!callerFg && r.app == null && mAm.mUserController.hasStartedUserState(r.userId)) { // 获取启动服务所在进程 ProcessRecord proc = mAm.getProcessRecordLocked(r.processName, r.appInfo.uid, false); ... } else if (DEBUG_DELAYED_STARTS) { ... } return startServiceInnerLocked(smap, service, r, callerFg, addToStarting); } |
这里做的主要是启动服务前的准备工作,首先是解析Intent携带的参数,并将这些内容保存在用来描述Service的ServiceRecord对象中保存起来,并将该对象放到等待启动服务的列表中。然后调用startServiceInnerLocked启动服务。在上面调用retrieveServiceLocked函数解析的过程中先去判断AMS中是否存在参数为service对应的ServiceRecord对象,如果存在说明已经启动过该服务,如果不存在,说明是第一次启动该服务。
8.ActiveServices.startServiceInnerLocked
ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r, boolean callerFg, boolean addToStarting) throws TransactionTooLargeException { ServiceState stracker = r.getTracker();// 获取服务状态 ... r.callStart = false;// 是否调用onStart方法 ... // 启动ServiceRecord对象r所描述的一个Service组件,即Server组件 String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false); ... return r.name; } |
这里比较简单主要是调用bringUpServiceLocked唤起服务。
Step9.ActiveServices.bringUpServiceLocked
private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg, boolean whileRestarting, boolean permissionsReviewRequired) throws TransactionTooLargeException { // 这里的r.app.thread是一个ApplicationThread对象,ApplicationThread是用来AMS和应用进程通信的工具, // 如果服务中的这个thread不为空说明已经和该Service存在通信了,也就是说已经启动了该服务了。 // 如果服务已经存在,调用startService的时候会执行Service.onStartCommand, // 只有首次启动服务才会调用onCreate方法 if (r.app != null && r.app.thread != null) { // 执行Service.onStartCommand方法过程 sendServiceArgsLocked(r, execInFg, false); return null; } ... // Make sure that the user who owns this service is started. If not, // we don't want to allow it to run. // 确保正在启动服务的用户已经启动,否则不允许执行 if (!mAm.mUserController.hasStartedUserState(r.userId)) { ... bringDownServiceLocked(r); return msg; } ... // 是不是独立进程 final boolean isolated = (r.serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0; // 首先获取ServiceRecord对象r所描述的Service组件的android:process属性,并保存在procName中 final String procName = r.processName; ProcessRecord app; if (!isolated) {// 要启动的服务不是独立进程 // 如果不是独立进程,通过进程名称和uid查找是否已经存在一个对应的ProcessRecord对象app,如果存在, // 说明用来运行这个Service组件的应用进程已经存在了,因此下面的realStartServiceLocked函数在 // ProcessRecord对象app所描述的应用程序进程中启动这个Service组件。 app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); if (app != null && app.thread != null) {// 进程存在,并且该进程已经与AMS通信过,那么直接启动服务 try { ... // 启动服务 realStartServiceLocked(r, app, execInFg); return null; } catch (TransactionTooLargeException e) { ... } // If a dead object exception was thrown -- fall through to // restart the application. } } else {// 如果要启动的进程是独立进程 ... } // 如果要启动的Service所在进程没有启动 if (app == null && !permissionsReviewRequired) { // 启动Service所需要的进程 if ((app = mAm.startProcessLocked(procName, r.appInfo, true, intentFlags, "service", r.name, false, isolated, false)) == null) { ... // 启动失败 bringDownServiceLocked(r); return msg; } ... } ... if (r.delayedStop) {// 如果是延迟停止的服务 // Oh and hey we've already been asked to stop! r.delayedStop = false; if (r.startRequested) { // 停止服务 stopServiceLocked(r); } } return null; } |
这里是启动服务最重要的部分,根据不同的情况进行不同的处理。首先是判断服务所在进程是否存在,如果存在调用sendServiceArgsLocked方法,最终根据条件,如果服务存在调用服务的onStartCommand方法;然后判断被启动服务的用户是否已经被启动,如果没有则停止服务,也就是调用bringDownServiceLocked方法,最终调用服务的onDestroy方法;然后判断非独立进程的服务,如果进程存在并且服务未启动的开始正式启动服务,调用realStartServiceLocked方法,最终调用onCreate方法;然后判断如果进程不存在,要启动进程,并且在app启动后启动服务,这里会调用启动失败,停止启动,因为进程启动后会启动该服务,这个过程在前面我们讲过,这里不再分析这种情况。最后是如果是延迟停止的服务这里直接停止该服务。下面我们按顺序分析这几种情况。
Step10.ActiveServices.sendServiceArgsLocked
private final void sendServiceArgsLocked(ServiceRecord r, boolean execInFg, boolean oomAdjusted) throws TransactionTooLargeException { // 等待启动服务个数 final int N = r.pendingStarts.size(); if (N == 0) { return; } while (r.pendingStarts.size() > 0) { ... try { .. // 标记启动服务开始 bumpServiceExecutingLocked(r, execInFg, "start"); ... // 发送消息,传动到ApplicationThread中的scheduleServiceArgs方法,最终会调用onStartCommand r.app.thread.scheduleServiceArgs(r, si.taskRemoved, si.id, flags, si.intent); } catch (TransactionTooLargeException e) { ... } } } |
上面Step5提到启动的服务都要先放到等待启动服务列表中,因此这里先判断服务列表是否存在要启动的服务,如果不存在则不再继续执行,如果存在,循环启动服务,这里调用scheduleServiceArgs方法,其实在前面分析了很多遍,最终会发送消息ActivityThread中的Handler中的handleMessage中进行处理,然后调用ActivityThread中的handleServiceArgs方法。
Step13.ActivityThread.handleServiceArgs
private void handleServiceArgs(ServiceArgsData data) { // 获取Service对象 Service s = mServices.get(data.token); if (s != null) { try { ... if (!data.taskRemoved) {// 任务没有被移除的话,调用Service.onStartCommand方法 res = s.onStartCommand(data.args, data.flags, data.startId); } else {// 否则调用被移除方法 s.onTaskRemoved(data.args); res = Service.START_TASK_REMOVED_COMPLETE; } ... } catch (Exception e) { ... } } } |
根据Service对应的token去缓存中获取服务,如果有该服务那么调用服务的onStartCommand方法,如果不存在那么就要继续往下走创建服务。
Step15.ActiveServices.bringDownServiceLocked
这个方法主要是处理停止服务的方法,里面主要是断开连接,解除绑定,然后销毁服务,因为这个过程是在服务停止时会调用,所以在后面介绍,这里先不介绍了。
Step16.ActiveServices.realStartServiceLocked
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { ... boolean created = false; ... // 发送信息到主线程,准备调用Service.onCreate方法 // 请求ProcessRecord对象app描述的应用程序进程将ServiceRecord独享r所描述的Service组件启动起来。 // ServiceRecord对象r所描述的Service组件启动完成之后,AMS就需要将它连接到一个请求绑定它的一个 // Activity组件中,这是通过调用AMS类的另一个成员函数requestServiceBindingLocked来实现的 app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); ... // 准备调用Service.onBind方法 requestServiceBindingsLocked(r, execInFg); ... // 准备调用Service.onStartCommand方法 sendServiceArgsLocked(r, execInFg, true); ... } |
启动服务调用三个方法,首先是通过app.thread.scheduleCreateService方法调用onCreate方法,然后通过requestServiceBindingsLocked方法调用Service.onBind方法,然后通过sendServiceArgsLocked方法调用Service.onStartCommand方法,其中最后一个方法我们分析过了,所以我们只分析前两个。第一很简单了,最终调用ActivityThread中的handleCreateService方法。
Step18.ActivityThread.handleCreateService
private void handleCreateService(CreateServiceData data) { ... // 获取一个用来描述即将要启动的Service组件所在的应用程序的LoadedApk对象,并将它保存在packageInfo // 变量中(每一个应用程序都使用一个LoadedApk对象来描述,通过它就能方位到它所描述的应用程序的资源) LoadedApk packageInfo = getPackageInfoNoCheck( data.info.applicationInfo, data.compatInfo); Service service = null; ... // 获取类加载器 java.lang.ClassLoader cl = packageInfo.getClassLoader(); // 通过类加载器将CreateServiceData对象data描述的一个Service组件加载的内存中,并且创建它的一个 // 实例,保存在Service对象service中。因为CreateServiceData对象data描述的Service组件即为应用 // 程序的Ashmem中的Server组件,因此,Service对象service指向的Service组件实际上是一个Server组件 service = (Service) cl.loadClass(data.info.name).newInstance(); ... // 初始化一个ContextImpl对象context,用来为前面所创建的Service对象service的运行上下文环境, // 通过它可以访问特定的应用程序资源,以及启动其他应用程序组件 ContextImpl context = ContextImpl.createAppContext(this, packageInfo); context.setOuterContext(service); // 创建一个Application对象app,用来描述Service对象service所属的应用程序。 Application app = packageInfo.makeApplication(false, mInstrumentation); // 使用Application对象app,ContextImpl对象context和CreateServiceData对象data来初始化 // Service对象service service.attach(context, this, data.info.name, data.token, app, ActivityManagerNative.getDefault()); // 调用Service的onCreate方法 service.onCreate(); // 以token为关键字保存Service对象service到mServices中,服务启动完成 mServices.put(data.token, service); ... } catch (Exception e) { ... } } |
首先获取LoadedApk对象,然后通过类加载器加载Service类,初始化Context,获取对应的Application,如果存在直接返回,如果该应用还没启动则直接创建该Application,然后通过Service的attach方法将对应的信息放置到Service中,这里面就包含ActivityThread,因此我们在Step9中可以通过这个来判断Service是不是被启动了,然后调用onCreate方法,创建完成后,将该服务以token为键,Service为值放入到缓存中,这样我们前面获取的时候就只从这里获取的,因此如果服务启动了换粗就会存在,否则不存在。下面我们分析onBind方法。
Step20.ActiveServices.requestServiceBindingsLocked
// 参数r指向一个ServiceRecord,表示一个已经启动的Service组件 private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) throws TransactionTooLargeException { for (int i = r.bindings.size() - 1; i >= 0; i--) { // 每一个IntentBindRecord对象都用来描述若干个需要将ServiceRecord对象r所描述的Service组件 // 绑定到它们里面的应用程序进程 IntentBindRecord ibr = r.bindings.valueAt(i); if (!requestServiceBindingLocked(r, ibr, execInFg, false)) { break; } } } |
for循环调用onBind。
Step21.ActiveServices.requestServiceBindingLocked
// 参数rebind表示是否需要将ServiceRecord对象r所描述的Service组件重新绑定到IntentBindRecord对象i // 所描述的应用程序进程中如果为false,则说明为第一绑定 private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) throws TransactionTooLargeException { ... // 检查AMS是否已经为IntentBindRecord对象i所描述的应用程序进程请求过ServiceRecord对象r所描述的 // Service组件返回其内部的一个Binder本地对象。如果还没有请求requested为false并且apps的数量大于0 if ((!i.requested || rebind) && i.apps.size() > 0) { try { ... //会执行到Service的onBind方法 r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState); if (!rebind) { // 设置为true,防止重复请求 i.requested = true; } ... } } return true; } |
这里通过调用r.app.thread.scheduleBindService方法,最终调用到ActivityThread中的handleBindService方法。
Step23.ActivityThread.handleBindService
private void handleBindService(BindServiceData data) { // 通过token来获得一个描述Service组件的Service对象 Service s = mServices.get(data.token); if (s != null) { try { ... if (!data.rebind) {// 首次绑定 // 获取一个实现了IBinder接口的Binder对象 IBinder binder = s.onBind(data.intent); ... } else { s.onRebind(data.intent); ... } ... } catch (Exception e) { ... } } } |
现获取服务,然后判断是再次绑定还是首次绑定,如果是首次绑定调用Service.onBind方法,如果是再次绑定调用Service.onRebind方法。到这里服务的启动就完成了,其他一些操作就不分析了。下面我们先分析另外一个启动流程bindService,最后分析停止服务流程。
Service启动流程-bindService
首先来看绑定流程时序图:
Step1.ContextImpl.bindService
public boolean bindService(Intent service, ServiceConnection conn, int flags) { warnIfCallingFromSystemProcess(); return bindServiceCommon(service, conn, flags, mMainThread.getHandler(), Process.myUserHandle()); } |
这里是绑定服务的入口位置,调用bindServiceCommon方法。
Step2.ContextImpl.bindServiceCommon
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, Handler handler, UserHandle user) { IServiceConnection sd; ... // mPackageInfo类型是LoadedApk if (mPackageInfo != null) { // 将ServiceConnection对象conn封装成一个实现了IServiceConnection接口的Binder本地对象sd sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); } else { ... } ... try { IBinder token = getActivityToken(); ... // 通过调用代理对象ActivityManagerProxy的bindService方法将前面获得的sd对象,以及Intent对象 // service等信息发送给AMS,以便AMS可以将ServiceConnection组件启动起来 int res = ActivityManagerNative.getDefault().bindService( mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, getOpPackageName(), user.getIdentifier()); ... return res != 0; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } |
首先调用LoadedApk中的getServiceDispatcher方法获取实现IServiceConnection接口的Binder对象ServiceDispatcher.InnerConnection。然后调用AMP中的bindService方法,然后通过Binder通信调用AMS中的bindService方法。
Step3.LoadedApk.getServiceDispatcher
// 每一个绑定过Service组件的Activity组件在LoadedApk类中都有一个对应的ServiceDispatcher对象,它负责将 // 这个被绑定的Service组件与绑定它的Activity组件关联起来,这些ServiceDispatcher保存在map中 public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); // 检查成员变量mServices中是否存在一个以ServiceConnection对象c为关键字的ServiceDispatcher // 对象sd,如果不存在,则创建一个并且以context为关键字保存到mServices中 if (map != null) { sd = map.get(c); } if (sd == null) { sd = new ServiceDispatcher(c, context, handler, flags); if (map == null) { map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } // 调用前面获取到的ServiceDispatcher对象sd的成员函数getIServiceConnection来获取一个实现了 // IServiceConnection接口的本地Binder对象 return sd.getIServiceConnection(); } } |
首先根据ServiceConnection取缓存中获取,如果没有要初始化一个ServiceDispatcher对象,然后获取ServiceDispatcher.InnerConnection对象并且返回。
Step6.AMP.bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String callingPackage, int userId) throws RemoteException { ... // 通过Binder对象mRemote向AMS发送一个类型为BIND_SERVICE_TRANSACTION的进程间通信请求 mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0); ... return res; } |
这里通过Binder调用AMS中对应的方法。
Step7.AMS.bindService
public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String callingPackage, int userId) throws TransactionTooLargeException { ... synchronized (this) { return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, callingPackage, userId); } } |
这里调用ActiveServices.bindServiceLocked方法。
Step8.ActiveServices.bindServiceLocked
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, final IServiceConnection connection, int flags, String callingPackage, final int userId) throws TransactionTooLargeException { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "bindService: " + service + " type=" + resolvedType + " conn=" + connection.asBinder() + " flags=0x" + Integer.toHexString(flags)); // 根据caller来获取一个ProcessRecord对象callerApp用来描述AMS执行绑定Service组件操作的一个Activity // 组件所运行在的应用程序进程 final ProcessRecord callerApp = mAm.getRecordForAppLocked(caller); ... ActivityRecord activity = null; if (token != null) { // 通过token来获得一个ActivityRecord对象activity,用来描述正在请求AMS执行绑定Service组件 // 操作的一个Activity组件 activity = ActivityRecord.isInStackLocked(token); if (activity == null) { Slog.w(TAG, "Binding with unknown activity: " + token); return 0; } } ... final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND; // 是否是绑定了外部服务,这个服务不是应用中的服务,而是外部独立的服务(我们通常启动服务都是应用内部的服务) final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0; // 根据参数service来得到一个ServiceRecord对象s,用来描述即将被绑定的Service组件 ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg, isBindExternal); ... // 调用ServiceRecord对象s的成员函数retrieveAppBindingLocked来得到一个AppBindRecord对象b, // 表示ServiceRecord对象s所描述的Service组件是绑定在ProcessRecord对象callerApp所描述的一个 // 应用程序进程中的 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); // 将前面获得的APPBindRecord对象、ActivityRecord对象Activity以及参数connection封装成一个 // ConnectionRecord对象s所描述的一个Service组件,并且这个Activity组件是运行在 // ProcessRecord对象callerApp所描述的一个应用进程中的 ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); // 由于一个Service组件可能会被同一个应用程序进程中的多个Activity组件使用同一个InnerConnection // 对象来绑定,因此,在AMS中,用来描述该Service组件的ServiceRecord对象就有可能会对应有多个 // ConnectionRecord对象。在这种情况下,这些ConnectionRecord对象就会被保存在一个列表中。 // 这个列表最终会保存在对应的ServiceRecord对象的成员变量Connection所描述的HashMap中,并且以 // 它里面的ConnectionRecord对象共同使用的一个InnerConnection代理对象的IBinder接口为关键字 // 参数connection是一个InnerConnection代理对象,因此可以获取它的一个IBinder接口binder IBinder binder = connection.asBinder(); // 检测在ServiceRecord对象s中是否存在一个以IBinder接口binder为关键字的列表clist,如果不存在 // 创建一个,并且将clist以binder为关键字放到ServiceRecord对象成员变量connections中 ArrayList<ConnectionRecord> clist = s.connections.get(binder); if (clist == null) {// 没有绑定过 clist = new ArrayList<ConnectionRecord>(); s.connections.put(binder, clist); } clist.add(c);// 添加绑定列表 b.connections.add(c);// 添加到关联应用和服务的对象AppBindRecord中记录绑定列表中 if (activity != null) { if (activity.connections == null) {// 这里判断Activity里面是否绑定过服务 activity.connections = new Has
热门推荐博文推荐热点聚焦 |