前面startService流程源码分析介绍了
startService
的启动流程,我们这一节来说说Service的绑定流程(基于Android10源码)。
- Service主要处理一些不与用户交互的耗时任务,比如I/O操作。Service分为两种,一种是通过
startService
来启动,另外一种是通过bindService
的形式来启动一个Service。本篇主要介绍bindService
启动流程源码分析 bindService
和startService
的结构很相似,两者可以比较着研究。
bindService的启动流程源码分析
- 一般我们绑定Service都是在一个Activity中开始的,我们就从这里开始分析。但是我们在Activity中并没有发现
bindService
方法,而是在它的父类ContextWrapper
中找到了这个方法,源码如下:@Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { return mBase.bindService(service, conn, flags); }
- 这里的
mBase
在Android深入理解Context一文中已经详细介绍了它的来历,这里其实是一种桥接模式,mBase其实就是真正实现了Context的ContextImpl
,这里就不详细叙述了。那么我们就直接看ContextImpl
中的bindService
。@Override public boolean bindService(Intent service, ServiceConnection conn, int flags) { warnIfCallingFromSystemProcess(); //-----1----- return bindServiceCommon(service, conn, flags, null, mMainThread.getHandler(), null, getUser()); } private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, String instanceName, Handler handler, Executor executor, UserHandle user) { // Keep this in sync with DevicePolicyManager.bindDeviceAdminServiceAsUser. IServiceConnection sd; if (conn == null) { throw new IllegalArgumentException("connection is null"); } if (handler != null && executor != null) { throw new IllegalArgumentException("Handler and Executor both supplied"); } if (mPackageInfo != null) { if (executor != null) { sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), executor, flags); } else { //-----2----- sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), handler, flags); } } else { throw new RuntimeException("Not supported in system context"); } validateServiceIntent(service); try { IBinder token = getActivityToken(); if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null && mPackageInfo.getApplicationInfo().targetSdkVersion < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) { flags |= BIND_WAIVE_PRIORITY; } service.prepareToLeaveProcess(this); //-----3----- int res = ActivityManager.getService().bindIsolatedServicebins( mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, instanceName, getOpPackageName(), user.getIdentifier()); if (res < 0) { throw new SecurityException( "Not allowed to bind to service " + service); } return res != 0; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
- 在注释
1
处我们发现调用了bindServiceCommon
。 - 在注释
2
处将客户端传进去的ServiceConnection
转换为了IServiceConnection
, 它是一个Binder, 之所以这么做是因为服务绑定是跨进程的,这个ServiceConnection
不能进行进程间的通信,得找到一个能进行进程间通信的Binder对象来回调ServiceConnection
中的方法,而ServiceDispatcher.InnerConnection
就是这样的一个角色,它继承了IServiceConnection.stub
,ServiceDispatcher
内部持有InnerConnection
和ServiceConnection
, 这样的话在需要的时候就会通过InnerConnection
调取ServiceConnection
中的方法达到目的。 - 获取
ServiceDispatcher
的源码如下:private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>> mServices = new ArrayMap<>(); @UnsupportedAppUsage public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) { return getServiceDispatcherCommon(c, context, handler, null, flags); } private IServiceConnection getServiceDispatcherCommon(ServiceConnection c, Context context, Handler handler, Executor executor, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context); if (map != null) { if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c); sd = map.get(c); } if (sd == null) { if (executor != null) { sd = new ServiceDispatcher(c, context, executor, flags); } else { sd = new ServiceDispatcher(c, context, handler, flags); } if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c); if (map == null) { map = new ArrayMap<>(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler, executor); } return sd.getIServiceConnection(); } }
- 在获取
ServiceDispatcher
过程中,有一个mServices
成员变量,这个变量是一个ArrayMap类型的,它存储了ServiceConnection
和LoadedApk.ServiceDispatcher
之间的映射关系。首先判断是否有这个映射关系,如果有的话就直接返回,如果没有的话就创建ServiceDispatcher
, 并且将其存储到mServices
中。 - 接着进入到注释
3
的ActivityManager.getService()
, 在Activity启动流程源码分析一文中我们说到了这里其实是得到了一个ActivityManagerService(下文简称AMS)
,接着我们进入AMS的bindIsolatedService
中看看。public int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String instanceName, String callingPackage, int userId) throws TransactionTooLargeException { enforceNotIsolatedCaller("bindService"); // 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"); } // Ensure that instanceName, which is caller provided, does not contain // unusual characters. if (instanceName != null) { for (int i = 0; i < instanceName.length(); ++i) { char c = instanceName.charAt(i); if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '.')) { throw new IllegalArgumentException("Illegal instanceName"); } } } synchronized(this) { return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, instanceName, callingPackage, userId); } }
- 我们看到在最后调用了
mServices.bindServiceLocked
,这里mServices是ActivteServices类型的
,我们上一篇Service流程源码分析(一) startService中有所介绍。下面接着看这个bindServiceLocked
。int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, final IServiceConnection connection, int flags, String instanceName, String callingPackage, final int userId) throws TransactionTooLargeException { ... //-----1----- if ((flags&Context.BIND_AUTO_CREATE) != 0) { s.lastActivity = SystemClock.uptimeMillis(); if (bringUpServiceLocked(s, service.getFlags(), callerFg, false, permissionsReviewRequired) != null) { return 0; } } //-----2----- if (s.app != null && b.intent.received) { // Service is already running, so we can immediately // publish the connection. try { c.conn.connected(s.name, b.intent.binder, false); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + s.shortInstanceName + " to connection " + c.conn.asBinder() + " (in " + c.binding.client.processName + ")", e); } // If this is the first app connected back to this binding, // and the service had previously asked to be told when // rebound, then do so. if (b.intent.apps.size() == 1 && b.intent.doRebind) { //-----3----- requestServiceBindingLocked(s, b.intent, callerFg, true); } } else if (!b.intent.requested) { //-----4----- requestServiceBindingLocked(s, b.intent, callerFg, false); } getServiceMapLocked(s.userId).ensureNotStartingBackgroundLocked(s); } finally { Binder.restoreCallingIdentity(origId); } return 1; }
- 在注释
1
处,我们根据Context.BIND_AUTO_CREATE
进行判断,这个标记是在我们调用bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE)
传入的最后一个参数,所以这里会进入bringUpServiceLocked
, 这里怎么看着这么熟悉呢,没错,这个方法我们在Service流程源码分析(一) startService中是重点分析的对象,也就是这个方法最终执行的service.onCreate()
, 这里bindService
自然也是要执行onCreate
的,这里就不详细介绍了,不懂的可以看那篇文章熟悉一下bringUpServiceLocked
的流程。 - 注释
2
的地方根据s.app != null && b.intent.received
进行判断,但是最终都会执行3
或者4
处的requestServiceBindingLocked
方法。在讲解requestServiceBindingLocked
之前,我们提一下这两个判断条件。 s.app
是ProcessRecord
类型,它在bringUpServiceLocked -> realStartServiceLocked
中的开始被赋值,源码如下注释1
处,所以是在requestServiceBindingLocked
之前就被赋值了,这里s.app!=null
为true
。private final void realStartServiceLocked(ServiceRecord r, ProcessRecord app, boolean execInFg) throws RemoteException { if (app.thread == null) { throw new RemoteException(); } ... //-----1----- r.setProcess(app); ...
b.intent.received
是一个boolean类型的,默认为false,它是在什么时候被赋值为true的呢 ?它是在当收到请求binder的时候被赋值为true, 这里很明显还是false, 所以实际上走的是上面注释4
处的requestServiceBindingLocked
, 因为b.intent.requested
默认为false。其实这两个值都是在ActivityThread.handleBindService -> ActivityManager.getService().publishService -> mServices.publishServiceLocked
中赋值的,这里很明显没有进入到这里,所以都还是false, 感兴趣的可以看看这部分源码。- 好了,我们接着看
requestServiceBindingLocked
部分的源码。private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) throws TransactionTooLargeException { if (r.app == null || r.app.thread == null) { // If service is not currently running, can't yet bind. return false; } if (DEBUG_SERVICE) Slog.d(TAG_SERVICE, "requestBind " + i + ": requested=" + i.requested + " rebind=" + rebind); if ((!i.requested || rebind) && i.apps.size() > 0) { try { bumpServiceExecutingLocked(r, execInFg, "bind"); r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE); //-----1----- r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind, r.app.getReportedProcState()); if (!rebind) { i.requested = true; } i.hasBound = true; i.doRebind = false; } catch (TransactionTooLargeException e) { // Keep the executeNesting count accurate. if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r, e); final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying); throw e; } catch (RemoteException e) { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Crashed while binding " + r); // Keep the executeNesting count accurate. final boolean inDestroying = mDestroyingServices.contains(r); serviceDoneExecutingLocked(r, inDestroying, inDestroying); return false; } } return true; } public final void scheduleBindService(IBinder token, Intent intent, boolean rebind, int processState) { updateProcessState(processState, false); BindServiceData s = new BindServiceData(); s.token = token; s.intent = intent; s.rebind = rebind; if (DEBUG_SERVICE) Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid=" + Binder.getCallingUid() + " pid=" + Binder.getCallingPid()); sendMessage(H.BIND_SERVICE, s); } case BIND_SERVICE: Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "serviceBind"); handleBindService((BindServiceData)msg.obj); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); break;
- H是前面文章介绍过了,它是一个Handler, 通过Handler机制来处理消息,我们看到接着会调用
handleBindService
来进行处理,我们进入这个方法看看。private void handleBindService(BindServiceData data) { //-----1----- Service s = mServices.get(data.token); if (DEBUG_SERVICE) Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind); if (s != null) { try { data.intent.setExtrasClassLoader(s.getClassLoader()); data.intent.prepareToEnterProcess(); try { if (!data.rebind) { //-----2----- IBinder binder = s.onBind(data.intent); //-----3----- ActivityManager.getService().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); ActivityManager.getService().serviceDoneExecuting( data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0); } } catch (RemoteException ex) { throw ex.rethrowFromSystemServer(); } } catch (Exception e) { if (!mInstrumentation.onException(s, e)) { throw new RuntimeException( "Unable to bind to service " + s + " with " + data.intent + ": " + e.toString(), e); } } } }
- 注释
1
处获取之前在handleCreateService
中存入的service。 - 在注释
2
的s.onBind(data.intent)
我们已经很熟悉了, 它返回一个我们自己创建的Binder对象给客户端。这个时候客户端和服务端其实已经绑定上了,但是onBind是在服务端调用的,客户端并不知道已经绑定成功了,需要执行我们自己创建的ServiceConnection.onServiceConnected
告知客户端,这些逻辑就在注释3
中。 - 我们查看注释
3
中ActivityManager.getService().publishService
源码。public void publishService(IBinder token, Intent intent, IBinder service) { // Refuse possible leaked file descriptors if (intent != null && intent.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } synchronized(this) { if (!(token instanceof ServiceRecord)) { throw new IllegalArgumentException("Invalid service token"); } //-----1----- mServices.publishServiceLocked((ServiceRecord)token, intent, service); } } void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) { final long origId = Binder.clearCallingIdentity(); try { if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "PUBLISHING " + r + " " + intent + ": " + service); if (r != null) { 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; ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections(); for (int conni = connections.size() - 1; conni >= 0; conni--) { ArrayList<ConnectionRecord> clist = connections.valueAt(conni); for (int i=0; i<clist.size(); i++) { ConnectionRecord c = clist.get(i); if (!filter.equals(c.binding.intent.intent)) { if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Not publishing to: " + c); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Bound intent: " + c.binding.intent.intent); if (DEBUG_SERVICE) Slog.v( TAG_SERVICE, "Published intent: " + intent); continue; } if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c); try { //-----2----- c.conn.connected(r.name, service, false); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + r.shortInstanceName + " to connection " + c.conn.asBinder() + " (in " + c.binding.client.processName + ")", e); } } } } serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false); } } finally { Binder.restoreCallingIdentity(origId); } }
- 代码进入到了注释
1
处的publishServiceLocked
,交给了ActiveServices
进行处理。 - 接着进入到了注释
2
处的c.conn.connected(r.name, service, false);
。这一行可以说是重点。c.conn
是ServiceDispatcher.InnerConnection
类型,这里又传入了onBind返回的service
对象。下面看一下这个InnerConnection.connected
源码。private static class InnerConnection extends IServiceConnection.Stub { @UnsupportedAppUsage final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; InnerConnection(LoadedApk.ServiceDispatcher sd) { mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); } public void connected(ComponentName name, IBinder service, boolean dead) throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd != null) { sd.connected(name, service, dead); } } }
- 我们看到又调用了
sd.connected(name, service, dead)
, 源码如下。public void connected(ComponentName name, IBinder service, boolean dead) { if (mActivityExecutor != null) { mActivityExecutor.execute(new RunConnection(name, service, 0, dead)); } else if (mActivityThread != null) { mActivityThread.post(new RunConnection(name, service, 0, dead)); } else { doConnected(name, service, dead); } }
- 这里
mActivityExecutor
和mActivityThread
在一开始我们调用bindService
的时候,调用了ContextImpl.bindService
,mActivityExecutor
是null,mActivityThread
是一个Handler, 其实就是ActivityThread中的H
,所以不为null, 所以这里进入了第二个mActivityThread != null
中,执行了RunConnection
中的run
方法。源码如下。private final class RunConnection implements Runnable { RunConnection(ComponentName name, IBinder service, int command, boolean dead) { mName = name; mService = service; mCommand = command; mDead = dead; } public void run() { if (mCommand == 0) { //-----1----- doConnected(mName, mService, mDead); } else if (mCommand == 1) { doDeath(mName, mService); } } final ComponentName mName; final IBinder mService; final int mCommand; final boolean mDead; }
- 这里很清楚调用了
doConnected(mName, mService, mDead)
方法,源码如下:public void doConnected(ComponentName name, IBinder service, boolean dead) { ServiceDispatcher.ConnectionInfo old; ServiceDispatcher.ConnectionInfo info; ... // If there is a new viable service, it is now connected. if (service != null) { mConnection.onServiceConnected(name, service); } else { // The binding machinery worked, but the remote returned null from onBind(). mConnection.onNullBinding(name); } }
- 上面的源码中
doConnected
是ServiceDispatcher
的方法,前面讲到,它存储了ServiceConnection
, 所以很容易就调用到了onServiceConnected
方,这是在客户端调用的,到这里bindService
也就分析完了,unbindService
比较简单,就不分析了。