我们知道,Android启动Service有两种方式,startService和bindService。
对于通过startService启动的Service,只能作为接收方,启动方可以通过onStartCommand来传递参数。这种启动方式其可以有多个启动者,不过在销毁的时候,一旦有任意一个启动调用了stopService或者自身stopSelf后,该Service就会停止,而启动者的生命周期无法影响到该Service。
对于通过bindService启动的Service,其和启动方有个“绑定”的过程,启动方可以通过Service的binder引用来调用Service的方法。不过这种方式Service的生命周期会关联着启动方的,启动方生命周期结束后,会默认unbindService来结束。
startService很多过程在bindService中都会得到体现,所以本文只介绍bindService的流程。
先看看bindService的调用过程
- bindService
- bindServiceCommon
这一步中首先会把ServiceConnection转成Binder对象
IServiceConnection sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags);
这一步是在LoadApk中完成的
public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; ArrayMapmap = mServices.get(context); if (map != null) { sd = map.get(c); } if (sd == null) { sd = new ServiceDispatcher(c, context, handler, flags); if (map == null) { map = new ArrayMap (); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } return sd.getIServiceConnection(); } }
可以看到,LoadApk会为每个context保存一个key为ServiceConnection、value为ServiceDispatcher的map,这样尽量做到了ServiceConnection对应的Binder对象的复用。如果没有可复用,则把ActivityThread的主Handler和ServiceConnection对应起来,这样在复用的时候,ServiceDispatcher会调用validate方法检查handler为当前主线程handler,保证不错乱。另外,ServiceConnection作为回调接口,其在IPC中实质是以ServiceDispatcher的内部类InnerConnection作为载体来代替的。
接下来,就交给ActivityManagerService处理了
int res = ActivityManagerNative.getDefault().bindService(mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, getOpPackageName(), user.getIdentifier());
ActiveService.bindServiceLocked
ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, callingPackage, Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg, isBindExternal); if (res == null) { return 0; } if (res.record == null) { return -1; }
这步顾名思义,是获取根据intent、binder等数据获取Service的信息,其中ServiceLookupResult包含了ServiceRecord和权限信息。进入函数我们可以看到如下:
ServiceRecord r = null; ServiceMap smap = getServiceMap(userId); final ComponentName comp = service.getComponent(); if (comp != null) { r = smap.mServicesByName.get(comp); } if (r == null && !isBindExternal) { Intent.FilterComparison filter = new Intent.FilterComparison(service); r = smap.mServicesByIntent.get(filter); } if (r != null && (r.serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0 && !callingPackage.equals(r.packageName)) { r = null; }
这一步可以看到,再取ServiceRecord的时候,会先去尝试用缓存,如果设置了FLAG_EXTERNAL_SERVICE且是外部Service调用,则禁止复用。如果无法复用,则创建新的ServiceRecord并赋值。
回到bindServiceLocked中,往下走
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
首先,ServiceRecord会根据自己的成员函数retrieveAppBindingLocked方法来获取一个AppBindRecord。再此后面会用到一些数据结构:AppBindRecord、ServiceRecord、IntentBindRecord、ProcessRecord、ConnectionRecord。他们之间的关系需要理清楚一下:
ServiceRecord:保存了Service的信息
ProcessRecord:进程的信息
ConnectionRecord:进程和Service建立起的本次通信,记一次ConnectionRecord
AppBindRecord:当某个进程需要用某个Intent启动Service的时候,这时候应用程序和Service的关系由AppBindRecord来维持。所以里面包含:谁启动(ProcessRecord)、启动的是哪个(ServiceRecord)、用什么来启动(IntentBindRecord)、所有启动记录的信息(ArraySet
IntentBindRecord:如在AppBindRecord所说,用什么来启动Service(Intent),里面携带了ServiceRecord、及所有用此Intent启动Service的ArrayMap
举个很不恰当的比喻:我想在一张纸上盖一个“汪毅雄”的章。
ProcessRecord:我(行为发起者)
ServiceRecord:“汪毅雄”的章印(行为目标)
IntentBindRecord:制作刻了“汪毅雄”三个字、并且能记录盖章过程的一个智能章。(工具,有权限的人都能用。也可以有很多个不同的,只要能盖出“汪毅雄”这几个字就可以)
AppBindRecord:“我要盖章”这个过程一系列下来的所有记录。
ConnectionRecord:手摁章印的过程。
public AppBindRecord retrieveAppBindingLocked(Intent intent, ProcessRecord app) { Intent.FilterComparison filter = new Intent.FilterComparison(intent); IntentBindRecord i = bindings.get(filter); if (i == null) { i = new IntentBindRecord(this, filter); bindings.put(filter, i); } AppBindRecord a = i.apps.get(app); if (a != null) { return a; } a = new AppBindRecord(this, i, app); i.apps.put(app, a); return a; }
有上面对数据结构的认识,我们可以看到,要取一个AppbindRecord。
- a、我们先用Intent去获取filter。
- b、ServiceRecord里有一个成员Map bindings保存所有可以启动该Service的IntentBindRecord,获得filter后,利用它去bindings中尝试复用IntentBindRecord。
- c、拿到IntentBindRecord后,再用ProcessRecord去检查IntentBindRecord,看看其里面有没有和ProcessRecord相同进程的且也是启动该Service的AppbindRecord,有的话当然不用再建一个AppBindRecord,直接复用返回。
继续往下
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); ConnectionRecord c = new ConnectionRecord(b, activity, connection, flags, clientLabel, clientIntent); IBinder binder = connection.asBinder(); ArrayListclist = s.connections.get(binder); if (clist == null) { clist = new ArrayList (); s.connections.put(binder, clist); } clist.add(c); b.connections.add(c); if (activity != null) { if (activity.connections == null) { activity.connections = new HashSet (); } activity.connections.add(c); }
获得AppBindRecord后,再利用传递过来的信息(包括IServiceConnection这个回调接口)创建一个ConnectionRecord,并且把ConnectionRecord分别保存到AppBindRecord、ServiceRecord、ActivityRecord中。
继续往下
if ((flags&Context.BIND_AUTO_CREATE) != 0) { s.lastActivity = SystemClock.uptimeMillis(); if (bringUpServiceLocked(s, service.getFlags(), callerFg, false, permissionsReviewRequired) != null) { return 0; } }
如果flag不为BIND_AUTO_CREATE,或者bringUpServiceLocked成功(return null)后,则可以继续后续的操作,如:Service已存在的时候BIND_TREAT_LIKE_ACTIVITY可以降低Service被杀的概率、重新回调connected、rebind等,本文不做讨论。继续bringUpServiceLocked
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false); if (app != null && app.thread != null) { try { app.addPackage(r.appInfo.packageName, r.appInfo.versionCode, mAm.mProcessStats); realStartServiceLocked(r, app, execInFg); return null; } catch (TransactionTooLargeException e) { throw e; } catch (RemoteException e) { } }
在realStartServiceLocked之前,和Activity启动一样,我们先需要判断Service的进程是否存在,如果不存在,需要孵化新的进程,然后再继续Service的启动。这块在Activity启动过程中已经详述,这里就不重复说了,详见《Android 7.0中Launcher启动Activity过程》
当进程存在的时候,我们直接realStartServiceLocked
mAm.notifyPackageUse(r.serviceInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_SERVICE); app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); r.postNotification(); created = true;
上面可以看到,这块利用binder通信去告诉进程去创建一个Service—scheduleCreateService,实际创建过程是在用户进程(ActivityThread)中。
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会创建一个CreateServiceData,并把ServiceInfo等信息填入,交给main Handler处理,最终会到handleCreateService方法中。我们直接进入
private void handleCreateService(CreateServiceData data) { 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 { 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()); service.onCreate(); mServices.put(data.token, service); try { ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } catch (Exception e) { ... } }
在这个方法中,首先获得Service的ClassLoader,用之load一个Service实例。然后再设置ContextImpl,然后初始化Service在进程中的信息和其binder对象,最后调用Service.onCreate方法,完成创建。然后通过binder告诉AMS service创建成功,也就是serviceDoneExecuting,可以看到告诉AMS的有个type的字段设为SERVICE_DONE_EXECUTING_ANON。
/** Type for IActivityManager.serviceDoneExecuting: anonymous operation */ public static final int SERVICE_DONE_EXECUTING_ANON = 0; /** Type for IActivityManager.serviceDoneExecuting: done with an onStart call */ public static final int SERVICE_DONE_EXECUTING_START = 1; /** Type for IActivityManager.serviceDoneExecuting: done stopping (destroying) service */ public static final int SERVICE_DONE_EXECUTING_STOP = 2;
这块是Service生命周期给AMS的回调的类型,有3类。但是在Service onCreate完成后,AMS收到后没太做处理,所以这部分跳过。
刚才在realStartServiceLocked,AMS告诉进程创建Service,但是步骤并没有真正完成,我们回到刚才的方法
private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { try { ... app.thread.scheduleCreateService(r, r.serviceInfo, mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo), app.repProcState); //******************** 接这里 ************************// } catch (DeadObjectException e) { ... } finally { ... } requestServiceBindingsLocked(r, execInFg); updateServiceClientActivitiesLocked(app, null, true); }
看到这里,在创建完成后,会调用requestServiceBindingsLocked方法执行bind操作
private final void requestServiceBindingsLocked(ServiceRecord r, boolean execInFg) throws TransactionTooLargeException { for (int i=r.bindings.size()-1; i>=0; i--) { IntentBindRecord ibr = r.bindings.valueAt(i); if (!requestServiceBindingLocked(r, ibr, execInFg, false)) { break; } } }
AMS进程中,会对bindings中的每一个IntentBindRecord尝试bind其进程。
if ((!i.requested || rebind) && i.apps.size() > 0) { try { bumpServiceExecutingLocked(r, execInFg, "bind"); r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.repProcState); if (!rebind) { i.requested = true; } i.hasBound = true; i.doRebind = false; } catch (TransactionTooLargeException e) { ... } catch (RemoteException e) { ... } }
通过binder告诉ActivityThread,Service需要执行bind操作。然后在ActivityThread会调用到handleBindService方法。
private void handleBindService(BindServiceData data) { Service s = mServices.get(data.token); if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); try { if (!data.rebind) { IBinder binder = s.onBind(data.intent); ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } ensureJitEnabled(); } catch (RemoteException ex) { } } catch (Exception e) { } } }
可以看到如果不是rebind,Service会执行Service.onBind()方法,把IntentBindRecord中的Intent告诉给Service谁bind它了。然后再告诉AMS publishService。
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) { Intent.FilterComparison filter = new Intent.FilterComparison(intent); IntentBindRecord b = r.bindings.get(filter); if (b != null && !b.received) { b.binder = service; b.requested = true; b.received = true; for (int conni = r.connections.size() - 1; conni >= 0; conni--) { ArrayListclist = r.connections.valueAt(conni); for (int i = 0; i < clist.size(); i++) { ConnectionRecord c = clist.get(i); ... try { c.conn.connected(r.name, service); } catch (Exception e) { } } } } }
在publishServiceLocked中,对所有ConnectionRecord,把bind结果回调给其IServiceConnection。而IService的Stub在LoadApk中
private static class InnerConnection extends IServiceConnection.Stub { final WeakReferencemDispatcher; public void connected(ComponentName name, IBinder service) throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd != null) { sd.connected(name, service); } } }
之后会通过主handler post一个Connection Runnable
private final class RunConnection implements Runnable { public void run() { if (mCommand == 0) { doConnected(mName, mService); } } }
最终真正执行到ServiceConnection中的onServiceConnected方法,完成最终绑定的过程
public void doConnected(ComponentName name, IBinder service) { if (service != null) { mConnection.onServiceConnected(name, service); } }
整个Service的bind过程就完成了!