ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
#### 9.3.2 Service的绑定过程 和Service的启动过程一样,Service的绑定过程也是从ContextWrapper开始的,如下所示。 public boolean bindService(Intent service, ServiceConnection conn, int flags) { return mBase.bindService(service, conn, flags); } 这个过程和Service的启动过程是类似的,mBase同样是ContextImpl类型的对象。ContextImpl的bindService方法最终会调用自己的bindServiceCommon方法,如下所示。 private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user) { IServiceConnection sd; if (conn == null) { throw new IllegalArgumentException("connection is null"); } if (mPackageInfo ! = null) { sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), mMainThread.getHandler(), 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(); int res = ActivityManagerNative.getDefault().bindService( mMainThread.getApplicationThread(), getActivityToken(), service, service.resolveTypeIfNeeded(getContentResolver()), sd, flags, user.getIdentifier()); if (res < 0) { throw new SecurityException( "Not allowed to bind to service " + service); } return res ! = 0; } catch (RemoteException e) { return false; } } bindServiceCommon方法主要完成如下两件事情。 首先将客户端的ServiceConnection对象转化为ServiceDispatcher.InnerConnection对象。之所以不能直接使用ServiceConnection对象,这是因为服务的绑定有可能是跨进程的,因此ServiceConnection对象必须借助于Binder才能让远程服务端回调自己的方法,而ServiceDispatcher的内部类InnerConnection刚好充当了Binder这个角色。那么ServiceDispatcher的作用是什么呢?其实ServiceDispatcher起着连接ServiceConnection和InnerConnection的作用。这个过程由LoadedApk的getServiceDispatcher方法来完成,它的实现如下: 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); 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.Service- Dispatcher>(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } return sd.getIServiceConnection(); } } 在上面的代码中,mServices是一个ArrayMap,它存储了一个应用当前活动的ServiceConnection和ServiceDispatcher的映射关系,它的定义如下所示。 private final ArrayMap<Context, ArrayMap<ServiceConnection, LoadedApk. ServiceDispatcher>> mServices = new ArrayMap<Context, ArrayMap <ServiceConnection, LoadedApk.ServiceDispatcher>>(); 系统首先会查找是否存在相同的ServiceConnection,如果不存在就重新创建一个ServiceDispatcher对象并将其存储在mServices中,其中映射关系的key是ServiceConnection, value是ServiceDispatcher,在ServiceDispatcher的内部又保存了ServiceConnection和InnerConnection对象。当Service和客户端建立连接后,系统会通过InnerConnection来调用ServiceConnection中的onServiceConnected方法,这个过程 有可能是跨进程的。当ServiceDispatcher创建好了以后,getServiceDispatcher会返回其保存的InnerConnection对象。 接着bindServiceCommon方法会通过AMS来完成Service的具体的绑定过程,这对应于AMS的bindService方法,如下所示。 public int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { enforceNotIsolatedCaller("bindService"); // Refuse possible leaked file descriptors if (service ! = null && service.hasFileDescriptors() == true) { throw new IllegalArgumentException("File descriptors passed in Intent"); } synchronized(this) { return mServices.bindServiceLocked(caller, token, service, resolvedType, connection, flags, userId); } } 接下来,AMS会调用ActiveServices的bindServiceLocked方法,bindServiceLocked再调用bringUpServiceLocked, bringUpServiceLocked又会调用realStartServiceLocked方法,realStartServiceLocked方法的执行逻辑和9.3.1节中的逻辑类似,最终都是通过ApplicationThread来完成Service实例的创建并执行其onCreate方法,这里不再重复讲解了。和启动Service不同的是,Service的绑定过程会调用app.thread的scheduleBindService方法,这个过程的实现在ActiveServices的requestServiceBindingLocked方法中,如下所示。 private final boolean requestServiceBindingLocked(ServiceRecord r, IntentBindRecord i, boolean execInFg, boolean rebind) { if (r.app == null || r.app.thread == null) { // If service is not currently running, can't yet bind. return false; } 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 (RemoteException e) { if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r); return false; } } return true; } 在上述代码中,app.thread这个对象多次出现过,对于它我们应该再熟悉不过了,它实际上就是ApplicationThread。ApplicationThread的一系列以schedule开头的方法,其内部都是通过Handler H来中转的,对于scheduleBindService方法来说也是如此,它的实现如下所示。 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); } 在H内部,接收到BIND_SERVICE这类消息时,会交给ActivityThread的handleBind-Service方法来处理。在handleBindService中,首先根据Service的token取出Service对象,然后调用Service的onBind方法,Service的onBind方法会返回一个Binder对象给客户端使用,这个过程我们在Service的开发过程中应该都比较熟悉了。原则上来说,Service的onBind方法被调用以后,Service就处于绑定状态了,但是onBind方法是Service的方法,这个时候客户端并不知道已经成功连接Service了,所以还必须调用客户端的ServiceConnection中的onServiceConnected,这个过程是由ActivityManagerNative.getDefault()的publishService方法来完成的,而前面多次提到,ActivityManagerNative.getDefault()就是AMS。handleBindService的实现过程如下所示。 ``` private void handleBindService(BindServiceData data) { 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) { IBinder binder = s.onBind(data.intent); ActivityManagerNative.getDefault().publishService( data.token, data.intent, binder); } else { s.onRebind(data.intent); ActivityManagerNative.getDefault().serviceDoneExecuting( data.token, 0, 0, 0); } ensureJitEnabled(); } catch (RemoteException ex) { } } catch (Exception e) { if (! mInstrumentation.onException(s, e)) { throw new RuntimeException( "Unable to bind to service " + s + " with " + data.intent + ": " + e.toString(), e); } } } } ``` Service有一个特性,当多次绑定同一个Service时,Service的onBind方法只会执行一次,除非Service被终止了。当Service的onBind执行以后,系统还需要告知客户端已经成功连接Service了。根据上面的分析,这个过程由AMS的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"); } mServices.publishServiceLocked((ServiceRecord)token, intent, service); } } 从上面代码可以看出,AMS的publishService方法将具体的工作交给了ActiveServices类型的mServices对象来处理。ActiveServices的publishServiceLocked方法看起来很复杂,但其实核心代码就只有一句话:c.conn.connected(r.name, service),其中c的类型是ConnectionRecord, c.conn的类型是ServiceDispatcher.InnerConnection, service就是Service的onBind方法返回的Binder对象。为了分析具体的逻辑,下面看一下ServiceDispatcher. InnerConnection的定义,如下所示。 private static class InnerConnection extends IServiceConnection.Stub { final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; InnerConnection(LoadedApk.ServiceDispatcher sd) { mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); } public void connected(ComponentName name, IBinder service) throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd ! = null) { sd.connected(name, service); } } } 从InnerConnection的定义可以看出,它的connected方法又调用了ServiceDispatcher的connected方法,ServiceDispatcher的connected方法的实现如下所示。 public void connected(ComponentName name, IBinder service) { if (mActivityThread ! = null) { mActivityThread.post(new RunConnection(name, service, 0)); } else { doConnected(name, service); } } 对于Service的绑定过程来说,ServiceDispatcher的mActivityThread是一个Handler,其实它就是ActivityThread中的H,从前面ServiceDispatcher的创建过程来说,mActivityThread不会为null,这样一来,RunConnection就可以经由H的post方法从而运行在主线程中,因此,客户端ServiceConnection中的方法是在主线程被回调的。RunConnection的定义如下所示。 private final class RunConnection implements Runnable { RunConnection(ComponentName name, IBinder service, int command) { mName = name; mService = service; mCommand = command; } public void run() { if (mCommand == 0) { doConnected(mName, mService); } else if (mCommand == 1) { doDeath(mName, mService); } } final ComponentName mName; final IBinder mService; final int mCommand; } 很显然,RunConnection的run方法也是简单调用了ServiceDispatcher的doConnected方法,由于ServiceDispatcher内部保存了客户端的ServiceConnection对象,因此它可以很方便地调用ServiceConnection对象的onServiceConnected方法,如下所示。 // If there is a new service, it is now connected. if (service ! = null) { mConnection.onServiceConnected(name, service); } 客户端的onServiceConnected方法执行后,Service的绑定过程也就分析完成了,至于Service的停止过程和解除绑定的过程,系统的执行过程是类似的,读者可以自行分析源码,这里就不再分析了。