Android Service绑定过程完整分析
通常我们使用service都要和它通信,当想要与service通信的时候,那么service要处于绑定状态的。然后客户端可以拿到一个binder与服务端进行通信,这个过程是很自然的。
那你真的了解过service的绑定过程吗?为什么可以是binder和service通信?
同样的先看一张图大致了解一下,灰色背景框起来的是同一个类的方法,如下:
我们知道调用context的bindservice方法即可绑定一个service,而contextimpl是context的实现类。那接下来就从源码的角度分析service的绑定过程。
当然是从contextimpl的bindservice方法开始,如下:
@override public boolean bindservice(intent service, serviceconnection conn, int flags) { warnifcallingfromsystemprocess(); return bindservicecommon(service, conn, flags, mmainthread.gethandler(), process.myuserhandle()); }
在bindservice方法中又会转到bindservicecommon方法,将intent,serviceconnection对象传进。
那就看看bindservicecommon方法的实现。
private boolean bindservicecommon(intent service, serviceconnection conn, int flags, handler handler, userhandle user) { iserviceconnection sd; if (conn == null) { throw new illegalargumentexception("connection is null"); } if (mpackageinfo != null) { 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); int res = activitymanagernative.getdefault().bindservice( mmainthread.getapplicationthread(), getactivitytoken(), service, service.resolvetypeifneeded(getcontentresolver()), sd, flags, 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(); } }
在上述代码中,调用了mpackageinfo(loadedapk对象)的getservicedispatcher方法。从getservicedispatcher方法的名字可以看出是获取一个“服务分发者”。其实是根据这个“服务分发者”获取到一个binder对象的。
那现在就看到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.servicedispatcher>(); mservices.put(context, map); } map.put(c, sd); } else { sd.validate(context, handler); } return sd.getiserviceconnection(); } }
从getservicedispatcher方法的实现可以知道,serviceconnection和servicedispatcher构成了映射关系。当存储集合不为空的时候,根据传进的key,也就是serviceconnection,来取出对应的servicedispatcher对象。
当取出servicedispatcher对象后,最后一行代码是关键,
return sd.getiserviceconnection();
调用了servicedispatcher对象的getiserviceconnection方法。这个方法肯定是获取一个iserviceconnection的。
iserviceconnection getiserviceconnection() { return miserviceconnection; }
那么miserviceconnection是什么?现在就可以来看下servicedispatcher类了。servicedispatcher是loadedapk的内部类,里面封装了innerconnection和serviceconnection。如下:
static final class servicedispatcher { private final servicedispatcher.innerconnection miserviceconnection; private final serviceconnection mconnection; private final context mcontext; private final handler mactivitythread; private final serviceconnectionleaked mlocation; private final int mflags; private runtimeexception munbindlocation; private boolean mforgotten; 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); } 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>(); servicedispatcher(serviceconnection conn, context context, handler activitythread, int flags) { miserviceconnection = new innerconnection(this); mconnection = conn; mcontext = context; mactivitythread = activitythread; mlocation = new serviceconnectionleaked(null); mlocation.fillinstacktrace(); mflags = flags; } //代码省略 }
先看到servicedispatcher的构造方法,一个servicedispatcher关联一个innerconnection对象。而innerconnection呢?,它是一个binder,有一个很重要的connected方法。至于为什么要用binder,因为与service通信可能是跨进程的。
好,到了这里先总结一下:调用bindservice方法绑定服务,会转到bindservicecommon方法。
在bindservicecommon方法中,会调用loadedapk的getservicedispatcher方法,并将serviceconnection传进, 根据这个serviceconnection取出与其映射的servicedispatcher对象,最后调用这个servicedispatcher对象的getiserviceconnection方法获取与其关联的innerconnection对象并返回。简单点理解就是用serviceconnection换来了innerconnection。
现在回到bindservicecommon方法,可以看到绑定service的过程会转到activitymanagernative.getdefault()的bindservice方法,其实从抛出的异常类型remoteexception也可以知道与service通信可能是跨进程的,这个是很好理解的。
而activitymanagernative.getdefault()是activitymanagerservice,那么继续跟进activitymanagerservice的bindservice方法即可,如下:
public int bindservice(iapplicationthread caller, ibinder token, intent service, string resolvedtype, iserviceconnection connection, int flags, 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"); } synchronized(this) { return mservices.bindservicelocked(caller, token, service, resolvedtype, connection, flags, callingpackage, userid); } }
在上述代码中,绑定service的过程转到activeservices的bindservicelocked方法,那就跟进activeservices的bindservicelocked方法瞧瞧。如下:
int bindservicelocked(iapplicationthread caller, ibinder token, intent service, string resolvedtype, final iserviceconnection connection, int flags, string callingpackage, final int userid) throws transactiontoolargeexception { //代码省略 connectionrecord c = new connectionrecord(b, activity, connection, flags, clientlabel, clientintent); ibinder binder = connection.asbinder(); arraylist<connectionrecord> clist = s.connections.get(binder); if (clist == null) { clist = new arraylist<connectionrecord>(); s.connections.put(binder, clist); } clist.add(c); //代码省略 if ((flags&context.bind_auto_create) != 0) { s.lastactivity = systemclock.uptimemillis(); if (bringupservicelocked(s, service.getflags(), callerfg, false, permissionsreviewrequired) != null) { return 0; } } //代码省略 return 1; }
将connection对象封装在connectionrecord中,这里的connection就是上面提到的innerconnection对象。这一步很重要的。
然后调用了bringupservicelocked方法,那么就探探这个bringupservicelocked方法,
private string bringupservicelocked(servicerecord r, int intentflags, boolean execinfg, boolean whilerestarting, boolean permissionsreviewrequired) throws transactiontoolargeexception { //代码省略 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) { slog.w(tag, "exception when starting service " + r.shortname, e); } // if a dead object exception was thrown -- fall through to // restart the application. } //代码省略 return null; }
可以看到调用了realstartservicelocked方法,真正去启动service了。
那么跟进realstartservicelocked方法探探,如下:
private final void realstartservicelocked(servicerecord r, processrecord app, boolean execinfg) throws remoteexception { //代码省略 app.thread.schedulecreateservice(r, r.serviceinfo, mam.compatibilityinfoforpackagelocked(r.serviceinfo.applicationinfo), app.repprocstate); r.postnotification(); created = true; //代码省略 requestservicebindingslocked(r, execinfg); updateserviceclientactivitieslocked(app, null, true); // if the service is in the started state, and there are no // pending arguments, then fake up one so its onstartcommand() will // be called. if (r.startrequested && r.callstart && r.pendingstarts.size() == 0) { r.pendingstarts.add(new servicerecord.startitem(r, false, r.makenextstartid(), null, null)); } sendserviceargslocked(r, execinfg, true); //代码省略 }
这里会调用app.thread的schedulecreateservice方法去创建一个service,然后会回调service的生命周期方法,然而绑定service呢?
在上述代码中,找到一个requestservicebindingslocked方法,从名字看是请求绑定服务的意思,那么就是它没错了。
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; } } }
咦,我再按住ctrl+鼠标左键,点进去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 ((!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; } //代码省略 return true; }
r.app.thread调用了schedulebindservice方法来绑定服务,而r.app.thread是applicationthread,现在关注到 applicationthread即可,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); }
封装了待绑定的service的信息,并发送了一个消息给主线程,
public void handlemessage(message msg) { if (debug_messages) slog.v(tag, ">>> handling: " + codetostring(msg.what)); switch (msg.what) { //代码省略 case bind_service: trace.tracebegin(trace.trace_tag_activity_manager, "servicebind"); handlebindservice((bindservicedata)msg.obj); trace.traceend(trace.trace_tag_activity_manager); break; //代码省略 } }
调用了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, service_done_executing_anon, 0, 0); } ensurejitenabled(); } 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); } } } }
根据token获取到service,然后service回调onbind方法。结束了?
可是onbind方法返回了一个binder是用来干嘛的?
我们再看看activitymanagernative.getdefault()调用了publishservice方法做了什么工作,此时又回到了activitymanagerservice。
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); } }
又会交给activeservices处理,转到了publishservicelocked方法,那看到activeservices的publishservicelocked方法,
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; for (int conni=r.connections.size()-1; conni>=0; conni--) { arraylist<connectionrecord> clist = r.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 { c.conn.connected(r.name, service); } //代码省略 }
c.conn是什么? 它是一个innerconnection对象,对,就是那个那个binder,上面也贴出了代码,在activeservices的bindservicelocked方法中,innerconnection对象被封装在connectionrecord中。那么现在它调用了connected方法,就很好理解了。
innerconnection的connected方法如下:
public void connected(componentname name, ibinder service) throws remoteexception { loadedapk.servicedispatcher sd = mdispatcher.get(); if (sd != null) { sd.connected(name, service); } }
会调用servicedispatcher 的connected方法,如下
public void connected(componentname name, ibinder service) { if (mactivitythread != null) { mactivitythread.post(new runconnection(name, service, 0)); } else { doconnected(name, service); } }
从而activitythread会投递一个消息到主线程,此时就解决了跨进程通信。
那么你应该猜到了runconnection一定有在主线程回调的onserviceconnected方法,
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; }
咦,还不出现?继续跟进doconnected方法,
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. 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); } }
在最后一个if判断,终于找到了onserviceconnected方法!
总结一下,当service回调onbind方法,其实还没有结束,会转到activitymanagerservice,然后又会在activeservices的publishservicelocked方法中,从connectionrecord中取出innerconnection对象。有了innerconnection对象后,就回调了它的connected。在innerconnection的connected方法中,又会调用servicedispatcher的connected方法,在servicedispatcher的connected方法向主线程扔了一个消息,切换到了主线程,之后就在主线程中回调了客户端传进的serviceconnected对象的onserviceconnected方法。
至此, service的绑定过程分析完毕。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
上一篇: java 开发中网络编程之IP、URL详解及实例代码
下一篇: MyBatis框架简介