Android的服务(Service)(三)Service客户端的绑定与跨进程
(一)、Service的生命周期
(二)、Service的自动重启问题
(三)、Service与其客户端的绑定如何实现,即跨进程调用问题。
服务于客户端的绑定通过binder来实现的,就是客户端去bind服务。来看看ContextImpl的bindServiceCommon方法
private boolean bindServiceCommon(Intent service, ServiceConnection conn, int flags, UserHandle user) { IServiceConnection sd; if (mPackageInfo != null) { sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(), mMainThread.getHandler(), flags); } 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; } }然后会去LoadedApk.java里面会创建用于跨进程连接的binder对象,就是一个ServiceDispatcher的InnerConnection。
public final IServiceConnection getServiceDispatcher(ServiceConnection c, Context context, Handler handler, int flags) { synchronized (mServices) { LoadedApk.ServiceDispatcher sd = null; //这里用一个map将所有的连接记录都保存起来了 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.ServiceDispatcher>(); mServices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } return sd.getIServiceConnection(); } }
static final class ServiceDispatcher { private final ServiceDispatcher.InnerConnection mIServiceConnection; private final ServiceConnection mConnection; private static class ConnectionInfo { IBinder binder; IBinder.DeathRecipient deathMonitor; } private static class InnerConnection extends IServiceConnection.Stub { final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher; InnerConnection(LoadedApk.ServiceDispatcher sd) { mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd); } //这个方法就是在ActivityManagerService中执行绑定链接时的方法调用 //这里的service毫无疑问就是远程对象执行onBind时返回的那个咯 //所以这里才是服务端和客户端传递一个binder对象的通道,因为这个过程涉及到两个跨进程操作,所以这么设计是必须也是合理的 public void connected(ComponentName name, IBinder service) throws RemoteException { LoadedApk.ServiceDispatcher sd = mDispatcher.get(); if (sd != null) { sd.connected(name, service); } } } private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections = new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>(); ServiceConnection getServiceConnection() { return mConnection; } IServiceConnection getIServiceConnection() { return mIServiceConnection; } public void connected(ComponentName name, IBinder service) { if (mActivityThread != null) { mActivityThread.post(new RunConnection(name, service, 0)); } else { doConnected(name, service); } } public void death(ComponentName name, IBinder service) { ....................... } //实际执行connect public void doConnected(ComponentName name, IBinder service) { ServiceDispatcher.ConnectionInfo old; ServiceDispatcher.ConnectionInfo info; synchronized (this) { if (mForgotten) { // We unbound before receiving the connection; ignore // any connection received. return; } old = mActiveConnections.get(name); if (old != null && old.binder == service) { // Huh, already have this one. Oh well! return; } if (service != null) { // A new service is being connected... set it all up. mDied = false; info = new ConnectionInfo(); info.binder = service; info.deathMonitor = new DeathMonitor(name, service); try { service.linkToDeath(info.deathMonitor, 0); mActiveConnections.put(name, info); } catch (RemoteException e) { // This service was dead before we got it... just // don't do anything with it. mActiveConnections.remove(name); return; } } else { // The named service is being disconnected... clean up. mActiveConnections.remove(name); } if (old != null) { old.binder.unlinkToDeath(old.deathMonitor, 0); } } // If there was an old service, it is not disconnected. if (old != null) { mConnection.onServiceDisconnected(name); } // If there is a new service, it is now connected. // 眼熟了吧,这就是我们在绑定服务后获取远程对象代理的回调咯 if (service != null) { mConnection.onServiceConnected(name, service); } } public void doDeath(ComponentName name, IBinder service) { mConnection.onServiceDisconnected(name); } 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); } } } private final class DeathMonitor implements IBinder.DeathRecipient { DeathMonitor(ComponentName name, IBinder service) { mName = name; mService = service; } public void binderDied() { death(mName, mService); } final ComponentName mName; final IBinder mService; } }
后面就是bind操作了,前面讲生命周期时已经有提到过的,这里再把那个方法列一下:
int bindServiceLocked(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, int userId) { .................... ServiceLookupResult res = retrieveServiceLocked(service, resolvedType, Binder.getCallingPid(), Binder.getCallingUid(), userId, true, callerFg); .................... try { if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false)) { if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: " + s); } ................... //bindings中添加一起绑定请求,后续requestServiceBindingsLocked()流程中处理绑定接口 AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp); .................... if ((flags&Context.BIND_AUTO_CREATE) != 0) { s.lastActivity = SystemClock.uptimeMillis(); //如果携带的标志位中包含自动启动,则进行创建服务的操作,代码可以看前面,如果已经启动了,其实是什么操作也不干的 if (bringUpServiceLocked(s, service.getFlags(), callerFg, false) != null) { return 0; } } if (s.app != null) { // This could have made the service more important. mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client); mAm.updateOomAdjLocked(s.app); } if (s.app != null && b.intent.received) { // Service is already running, so we can immediately // publish the connection. // 如果服务已经启动并且有绑定过了,直接返回binder对象,这里的conn就是前面提到的InnerConnection的代理,这里看到了connected操作其实是由<pre name="code" class="java"> // InnerConnection它来完成的 try { c.conn.connected(s.name, b.intent.binder); } catch (Exception e) { Slog.w(TAG, "Failure sending service " + s.shortName + " 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. // 从这里可以看出,一般情况下,onBind只会执行一次,除非请求doRebind // 这个标志位是旧的客户端全部unbind之后自动设置上的 if (b.intent.apps.size() == 1 && b.intent.doRebind) { requestServiceBindingLocked(s, b.intent, callerFg, true); } } else if (!b.intent.requested) { //服务还没有绑定者,则执行后续操作将调用到onBind操作 requestServiceBindingLocked(s, b.intent, callerFg, false); } getServiceMap(s.userId).ensureNotStartingBackground(s); } finally { Binder.restoreCallingIdentity(origId); } return 1; }大家有没有在上面注意一个问题,InnerConnection中并没有unConnected方法,那么解绑的时候又是如何通过这个连接通道执行回调的呢?大家可以看看前面讲的unBind流程中,里面也是没有任何地方会执行到这个操作的,它有的只是服务端的unBind和可能执行onDestory。那么什么时候会执行到ServiceConnection.onServiceDisconnected,事实上只有在远程服务端那个binder死亡才会执行到的。这个就是通过为这个binder对象注册一个IBinder.DeathRecipient,这是binder的死亡通知机制。这里就不讲了。
到这里Android中的服务已经简要的分析了一下,不可能面面俱到也不会全都正确,还请大家多多指教。
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。