AndroidService的绑定过程
通常我们使用Service都要和它通信,当想要与Service通信的时候,那么Service要处于绑定状态的。然后客户端可以拿到一个Binder与服务端进行通信,这个过程是很自然的。
那你真的了解过Service的绑定过程吗?为什么可以是Binder和Service通信?
同样的先看一张图大致了解一下,灰色背景框起来的是同一个类的方法,如下:
我们知道调用Context的bindService方法即可绑定一个Service,而ContextImpl是Context的实现类。那接下来就从源码的角度分析Service的绑定过程。
当然是从ContextImpl的bindService方法开始,如下:
@Override
publicbooleanbindService(Intentservice,ServiceConnectionconn,
intflags){
warnIfCallingFromSystemProcess();
returnbindServiceCommon(service,conn,flags,mMainThread.getHandler(),
Process.myUserHandle());
}
在bindService方法中又会转到bindServiceCommon方法,将Intent,ServiceConnection对象传进。
那就看看bindServiceCommon方法的实现。
privatebooleanbindServiceCommon(Intentservice,ServiceConnectionconn,intflags,Handler
handler,UserHandleuser){
IServiceConnectionsd;
if(conn==null){
thrownewIllegalArgumentException("connectionisnull");
}
if(mPackageInfo!=null){
sd=mPackageInfo.getServiceDispatcher(conn,getOuterContext(),handler,flags);
}else{
thrownewRuntimeException("Notsupportedinsystemcontext");
}
validateServiceIntent(service);
try{
IBindertoken=getActivityToken();
if(token==null&&(flags&BIND_AUTO_CREATE)==0&&mPackageInfo!=null
&&mPackageInfo.getApplicationInfo().targetSdkVersion
flags|=BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess(this);
intres=ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(),getActivityToken(),service,
service.resolveTypeIfNeeded(getContentResolver()),
sd,flags,getOpPackageName(),user.getIdentifier());
if(res<0){
thrownewSecurityException(
"Notallowedtobindtoservice"+service);
}
returnres!=0;
}catch(RemoteExceptione){
throwe.rethrowFromSystemServer();
}
}
在上述代码中,调用了mPackageInfo(LoadedApk对象)的getServiceDispatcher方法。从getServiceDispatcher方法的名字可以看出是获取一个“服务分发者”。其实是根据这个“服务分发者”获取到一个Binder对象的。
那现在就看到getServiceDispatcher方法的实现。
publicfinalIServiceConnectiongetServiceDispatcher(ServiceConnectionc,
Contextcontext,Handlerhandler,intflags){
synchronized(mServices){
LoadedApk.ServiceDispatchersd=null;
ArrayMapmap=mServices.get(context);
if(map!=null){
sd=map.get(c);
}
if(sd==null){
sd=newServiceDispatcher(c,context,handler,flags);
if(map==null){
map=newArrayMap();
mServices.put(context,map);
}
map.put(c,sd);
}else{
sd.validate(context,handler);
}
returnsd.getIServiceConnection();
}
}
从getServiceDispatcher方法的实现可以知道,ServiceConnection和ServiceDispatcher构成了映射关系。当存储集合不为空的时候,根据传进的key,也就是ServiceConnection,来取出对应的ServiceDispatcher对象。
当取出ServiceDispatcher对象后,最后一行代码是关键,
returnsd.getIServiceConnection();
调用了ServiceDispatcher对象的getIServiceConnection方法。这个方法肯定是获取一个IServiceConnection的。
IServiceConnectiongetIServiceConnection(){
returnmIServiceConnection;
}
那么mIServiceConnection是什么?现在就可以来看下ServiceDispatcher类了。ServiceDispatcher是LoadedApk的内部类,里面封装了InnerConnection和ServiceConnection。如下:
staticfinalclassServiceDispatcher{
privatefinalServiceDispatcher.InnerConnectionmIServiceConnection;
privatefinalServiceConnectionmConnection;
privatefinalContextmContext;
privatefinalHandlermActivityThread;
privatefinalServiceConnectionLeakedmLocation;
privatefinalintmFlags;
privateRuntimeExceptionmUnbindLocation;
privatebooleanmForgotten;
privatestaticclassConnectionInfo{
IBinderbinder;
IBinder.DeathRecipientdeathMonitor;
}
privatestaticclassInnerConnectionextendsIServiceConnection.Stub{
finalWeakReferencemDispatcher;
InnerConnection(LoadedApk.ServiceDispatchersd){
mDispatcher=newWeakReference(sd);
}
publicvoidconnected(ComponentNamename,IBinderservice)throwsRemoteException{
LoadedApk.ServiceDispatchersd=mDispatcher.get();
if(sd!=null){
sd.connected(name,service);
}
}
}
privatefinalArrayMapmActiveConnections
=newArrayMap();
ServiceDispatcher(ServiceConnectionconn,
Contextcontext,HandleractivityThread,intflags){
mIServiceConnection=newInnerConnection(this);
mConnection=conn;
mContext=context;
mActivityThread=activityThread;
mLocation=newServiceConnectionLeaked(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方法即可,如下:
publicintbindService(IApplicationThreadcaller,IBindertoken,Intentservice,
StringresolvedType,IServiceConnectionconnection,intflags,StringcallingPackage,
intuserId)throwsTransactionTooLargeException{
enforceNotIsolatedCaller("bindService");
//Refusepossibleleakedfiledescriptors
if(service!=null&&service.hasFileDescriptors()==true){
thrownewIllegalArgumentException("FiledescriptorspassedinIntent");
}
if(callingPackage==null){
thrownewIllegalArgumentException("callingPackagecannotbenull");
}
synchronized(this){
returnmServices.bindServiceLocked(caller,token,service,
resolvedType,connection,flags,callingPackage,userId);
}
}
在上述代码中,绑定Service的过程转到ActiveServices的bindServiceLocked方法,那就跟进ActiveServices的bindServiceLocked方法瞧瞧。如下:
intbindServiceLocked(IApplicationThreadcaller,IBindertoken,Intentservice,
StringresolvedType,finalIServiceConnectionconnection,intflags,
StringcallingPackage,finalintuserId)throwsTransactionTooLargeException{
//代码省略
ConnectionRecordc=newConnectionRecord(b,activity,
connection,flags,clientLabel,clientIntent);
IBinderbinder=connection.asBinder();
ArrayListclist=s.connections.get(binder);
if(clist==null){
clist=newArrayList();
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){
return0;
}
}
//代码省略
return1;
}
将connection对象封装在ConnectionRecord中,这里的connection就是上面提到的InnerConnection对象。这一步很重要的。
然后调用了bringUpServiceLocked方法,那么就探探这个bringUpServiceLocked方法,
privateStringbringUpServiceLocked(ServiceRecordr,intintentFlags,booleanexecInFg,
booleanwhileRestarting,booleanpermissionsReviewRequired)
throwsTransactionTooLargeException{
//代码省略
if(app!=null&&app.thread!=null){
try{
app.addPackage(r.appInfo.packageName,r.appInfo.versionCode,mAm.mProcessStats);
realStartServiceLocked(r,app,execInFg);
returnnull;
}catch(TransactionTooLargeExceptione){
throwe;
}catch(RemoteExceptione){
Slog.w(TAG,"Exceptionwhenstartingservice"+r.shortName,e);
}
//Ifadeadobjectexceptionwasthrown--fallthroughto
//restarttheapplication.
}
//代码省略
returnnull;
}
可以看到调用了realStartServiceLocked方法,真正去启动Service了。
那么跟进realStartServiceLocked方法探探,如下:
privatefinalvoidrealStartServiceLocked(ServiceRecordr,
ProcessRecordapp,booleanexecInFg)throwsRemoteException{
//代码省略
app.thread.scheduleCreateService(r,r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created=true;
//代码省略
requestServiceBindingsLocked(r,execInFg);
updateServiceClientActivitiesLocked(app,null,true);
//Iftheserviceisinthestartedstate,andthereareno
//pendingarguments,thenfakeuponesoitsonStartCommand()will
//becalled.
if(r.startRequested&&r.callStart&&r.pendingStarts.size()==0){
r.pendingStarts.add(newServiceRecord.StartItem(r,false,r.makeNextStartId(),
null,null));
}
sendServiceArgsLocked(r,execInFg,true);
//代码省略
}
这里会调用app.thread的scheduleCreateService方法去创建一个Service,然后会回调Service的生命周期方法,然而绑定Service呢?
在上述代码中,找到一个requestServiceBindingsLocked方法,从名字看是请求绑定服务的意思,那么就是它没错了。
privatefinalvoidrequestServiceBindingsLocked(ServiceRecordr,booleanexecInFg)
throwsTransactionTooLargeException{
for(inti=r.bindings.size()-1;i>=0;i--){
IntentBindRecordibr=r.bindings.valueAt(i);
if(!requestServiceBindingLocked(r,ibr,execInFg,false)){
break;
}
}
}
咦,我再按住Ctrl+鼠标左键,点进去requestServiceBindingLocked方法。如下:
privatefinalbooleanrequestServiceBindingLocked(ServiceRecordr,IntentBindRecordi,
booleanexecInFg,booleanrebind)throwsTransactionTooLargeException{
if(r.app==null||r.app.thread==null){
//Ifserviceisnotcurrentlyrunning,can''tyetbind.
returnfalse;
}
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;
}
//代码省略
returntrue;
}
r.app.thread调用了scheduleBindService方法来绑定服务,而r.app.thread是ApplicationThread,现在关注到ApplicationThread即可,scheduleBindService方法如下:
publicfinalvoidscheduleBindService(IBindertoken,Intentintent,
booleanrebind,intprocessState){
updateProcessState(processState,false);
BindServiceDatas=newBindServiceData();
s.token=token;
s.intent=intent;
s.rebind=rebind;
if(DEBUG_SERVICE)
Slog.v(TAG,"scheduleBindServicetoken="+token+"intent="+intent+"uid="
+Binder.getCallingUid()+"pid="+Binder.getCallingPid());
sendMessage(H.BIND_SERVICE,s);
}
封装了待绑定的Service的信息,并发送了一个消息给主线程,
publicvoidhandleMessage(Messagemsg){
if(DEBUG_MESSAGES)Slog.v(TAG,">>>handling:"+codeToString(msg.what));
switch(msg.what){
//代码省略
caseBIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"serviceBind");
handleBindService((BindServiceData)mswww.shanxiwang.netg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
//代码省略
}
}
调用了handleBindService方法,即将绑定完成啦。
privatevoidhandleBindService(BindServiceDatadata){
Services=mServices.get(data.token);
if(DEBUG_SERVICE)
Slog.v(TAG,"handleBindServices="+s+"rebind="+data.rebind);
if(s!=null){
try{
data.intent.setExtrasClassLoader(s.getClassLoader());
data.intent.prepareToEnterProcess();
try{
if(!data.rebind){
IBinderbinder=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(RemoteExceptionex){
throwex.rethrowFromSystemServer();
}
}catch(Exceptione){
if(!mInstrumentation.onException(s,e)){
thrownewRuntimeException(
"Unabletobindtoservice"+s
+"with"+data.intent+":"+e.toString(),e);
}
}
}
}
根据token获取到Service,然后Service回调onBind方法。结束了?
可是onBind方法返回了一个binder是用来干嘛的?
我们再看看ActivityManagerNative.getDefault()调用了publishService方法做了什么工作,此时又回到了ActivityManagerService。
publicvoidpublishService(IBindertoken,Intentintent,IBinderservice){
//Refusepossibleleakedfiledescriptors
if(intent!=null&&intent.hasFileDescriptors()==true){
thrownewIllegalArgumentException("FiledescriptorspassedinIntent");
}
synchronized(this){
if(!(tokeninstanceofServiceRecord)){
thrownewIllegalArgumentException("Invalidservicetoken");
}
mServices.publishServiceLocked((ServiceRecord)token,intent,service);
}
}
又会交给ActiveServices处理,转到了publishServiceLocked方法,那看到ActiveServices的publishServiceLocked方法,
voidpublishServiceLocked(ServiceRecordr,Intentintent,IBinderservice){
finallongorigId=Binder.clearCallingIdentity();
try{
if(DEBUG_SERVICE)Slog.v(TAG_SERVICE,"PUBLISHING"+r
+""+intent+":"+service);
if(r!=null){
Intent.FilterComparisonfilter
=newIntent.FilterComparison(intent);
IntentBindRecordb=r.bindings.get(filter);
if(b!=null&&!b.received){
b.binder=service;
b.requested=true;
b.received=true;
for(intconni=r.connections.size()-1;conni>=0;conni--){
ArrayListclist=r.connections.valueAt(conni);
for(inti=0;i ConnectionRecordc=clist.get(i);
if(!filter.equals(c.binding.intent.intent)){
if(DEBUG_SERVICE)Slog.v(
TAG_SERVICE,"Notpublishingto:"+c);
if(DEBUG_SERVICE)Slog.v(
TAG_SERVICE,"Boundintent:"+c.binding.intent.intent);
if(DEBUG_SERVICE)Slog.v(
TAG_SERVICE,"Publishedintent:"+intent);
continue;
}
if(DEBUG_SERVICE)Slog.v(TAG_SERVICE,"Publishingto:"+c);
try{
c.conn.connected(r.name,service);
}
//代码省略
}
c.conn是什么?它是一个InnerConnection对象,对,就是那个那个Binder,上面也贴出了代码,在ActiveServices的bindServiceLocked方法中,InnerConnection对象被封装在ConnectionRecord中。那么现在它调用了connected方法,就很好理解了。
InnerConnection的connected方法如下:
publicvoidconnected(ComponentNamename,IBinderservice)throwsRemoteException{
LoadedApk.ServiceDispatchersd=mDispatcher.get();
if(sd!=null){
sd.connected(name,service);
}
}
会调用ServiceDispatcher的connected方法,如下
publicvoidconnected(ComponentNamename,IBinderservice){
if(mActivityThread!=null){
mActivityThread.post(newRunConnection(name,service,0));
}else{
doConnected(name,service);
}
}
从而ActivityThread会投递一个消息到主线程,此时就解决了跨进程通信。
那么你应该猜到了RunConnection一定有在主线程回调的onServiceConnected方法,
privatefinalclassRunConnectionimplementsRunnable{
RunConnection(ComponentNamename,IBinderservice,intcommand){
mName=name;
mService=service;
mCommand=command;
}
publicvoidrun(){
if(mCommand==0){
doConnected(mName,mService);
}elseif(mCommand==1){
doDeath(mName,mService);
}
}
finalComponentNamemName;
finalIBindermService;
finalintmCommand;
}
咦,还不出现?继续跟进doConnected方法,
publicvoiddoConnected(ComponentNamename,IBinderservice){
ServiceDispatcher.ConnectionInfoold;
ServiceDispatcher.ConnectionInfoinfo;
synchronized(this){
if(mForgotten){
//Weunboundbeforereceivingtheconnection;ignore
//anyconnectionreceived.
return;
}
old=mActiveConnections.get(name);
if(old!=null&&old.binder==service){
//Huh,alreadyhavethisone.Ohwell!
return;
}
if(service!=null){
//Anewserviceisbeingconnected...setitallup.
info=newConnectionInfo();
info.binder=service;
info.deathMonitor=newDeathMonitor(name,service);
try{
service.linkToDeath(info.deathMonitor,0);
mActiveConnections.put(name,info);
}catch(RemoteExceptione){
//Thisservicewasdeadbeforewegotit...just
//don''tdoanythingwithit.
mActiveConnections.remove(name);
return;
}
}else{
//Thenamedserviceisbeingdisconnected...cleanup.
mActiveConnections.remove(name);
}
if(old!=null){
old.binder.unlinkToDeath(old.deathMonitor,0);
}
}
//Iftherewasanoldservice,itisnotdisconnected.
if(old!=null){
mConnection.onServiceDisconnected(name);
}
//Ifthereisanewservice,itisnowconnected.
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的绑定过程分析完毕。
|
|