Android深入四大组件三Service的绑定过程.docx
《Android深入四大组件三Service的绑定过程.docx》由会员分享,可在线阅读,更多相关《Android深入四大组件三Service的绑定过程.docx(12页珍藏版)》请在冰豆网上搜索。
![Android深入四大组件三Service的绑定过程.docx](https://file1.bdocx.com/fileroot1/2023-2/1/abde34a8-04a6-462d-9681-b384a91b5d54/abde34a8-04a6-462d-9681-b384a91b5d541.gif)
Android深入四大组件三Service的绑定过程
Android深入四大组件(三)Service的绑定过程
1.ContextImpl到ActivityManageService的调用过程
我们可以用bindService方法来绑定Service,它的实现在ContextWrapper中,代码如下所示。
frameworks/base/core/Java/Android/content/ContextWrapper.java
@Override
publicbooleanbindService(Intentservice,ServiceConnectionconn,
intflags){
returnmBase.bindService(service,conn,flags);
}
查看ContextImpl的bindService方法:
frameworks/base/core/java/android/app/ContextImpl.java
@Override
publicbooleanbindService(Intentservice,ServiceConnectionconn,
intflags){
warnIfCallingFromSystemProcess();
returnbindServiceCommon(service,conn,flags,mMainThread.getHandler(),
Process.myUserHandle());
}
在bindService方法中,又return了bindServiceCommon方法,代码如下所示。
frameworks/base/core/java/android/app/ContextImpl.java
privatebooleanbindServiceCommon(Intentservice,ServiceConnectionconn,intflags,Handler
handler,UserHandleuser){
IServiceConnectionsd;
if(conn==null){
thrownewIllegalArgumentException("connectionisnull");
}
if(mPackageInfo!
=null){
sd=mPackageInfo.getServiceDispatcher(conn,getOuterContext(),handler,flags);//1
}else{
thrownewRuntimeException("Notsupportedinsystemcontext");
}
validateServiceIntent(service);
try{
...
/**
*2
*/
intres=ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(),getActivityToken(),service,
service.resolveTypeIfNeeded(getContentResolver()),
sd,flags,getOpPackageName(),user.getIdentifier());
...
}catch(RemoteExceptione){
throwe.rethrowFromSystemServer();
}
}
在注释1处调用了LoadedApk类型的对象mPackageInfo的getServiceDispatcher方法,它的主要作用是将ServiceConnection封装为IServiceConnection类型的对象sd,从IServiceConnection的名字我们就能得知它实现了Binder机制,这样Service的绑定就支持了跨进程。
接着在注释2处我们又看见了熟悉的代码,最终会调用AMS的bindService方法。
ContextImpl到ActivityManageService的调用过程如下面的时序图所示。
2.Service的绑定过程
AMS的bindService方法代码如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
publicintbindService(IApplicationThreadcaller,IBindertoken,Intentservice,
StringresolvedType,IServiceConnectionconnection,intflags,StringcallingPackage,
intuserId)throwsTransactionTooLargeException{
enforceNotIsolatedCaller("bindService");
...
synchronized(this){
returnmServices.bindServiceLocked(caller,token,service,
resolvedType,connection,flags,callingPackage,userId);
}
}
bindService方法最后会调用ActiveServices类型的对象mServices的bindServiceLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
intbindServiceLocked(IApplicationThreadcaller,IBindertoken,Intentservice,
StringresolvedType,finalIServiceConnectionconnection,intflags,
StringcallingPackage,finalintuserId)throwsTransactionTooLargeException{
...
if((flags&Context.BIND_AUTO_CREATE)!
=0){
s.lastActivity=SystemClock.uptimeMillis();
/**
*1
*/
if(bringUpServiceLocked(s,service.getFlags(),callerFg,false,
permissionsReviewRequired)!
=null){
return0;
}
}
...
if(s.app!
=null&&b.intent.received){//2
try{
c.conn.connected(s.name,b.intent.binder);//3
}catch(Exceptione){
...
}
if(b.intent.apps.size()==1&&b.intent.doRebind){//4
requestServiceBindingLocked(s,b.intent,callerFg,true);//5
}
}elseif(!
b.intent.requested){//6
requestServiceBindingLocked(s,b.intent,callerFg,false);//7
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
}finally{
Binder.restoreCallingIdentity(origId);
}
return1;
}
在注释1处会bringUpServiceLocked方法,在bringUpServiceLocked方法中又会调用realStartServiceLocked方法,最终由ActivityThread来调用Service的onCreate方法启动Service,
在注释2处s.app!
=null表示Service已经运行,其中s是ServiceRecord类型对象,app是ProcessRecord类型对象。
b.intent.received表示当前应用程序进程的Client端已经接收到绑定Service时返回的Binder,这样应用程序进程的Client端就可以通过Binder来获取要绑定的Service的访问接口。
注释3处调用c.conn的connected方法,其中c.conn指的是IServiceConnection,它的具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,InnerConnection的connected方法内部会调用H的post方法向主线程发送消息,从而解决当前应用程序进程和Service跨进程通信的问题,在后面会详细介绍这一过程。
在注释4处如果当前应用程序进程的Client端第一次与Service进行绑定的,并且Service已经调用过onUnBind方法,则需要调用注释5的代码。
注释6处如果应用程序进程的Client端没有发送过绑定Service的请求,则会调用注释7的代码,注释7和注释5的代码区别就是最后一个参数rebind为false,表示不是重新绑定。
接着我们查看注释7的requestServiceBindingLocked方法,代码如下所示。
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
privatefinalbooleanrequestServiceBindingLocked(ServiceRecordr,IntentBindRecordi,
booleanexecInFg,booleanrebind)throwsTransactionTooLargeException{
...
if((!
i.requested||rebind)&&i.apps.size()>0){//1
try{
bumpServiceExecutingLocked(r,execInFg,"bind");
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r,i.intent.getIntent(),rebind,
r.app.repProcState);//2
...
}
...
}
returntrue;
}
注释1处i.requested表示是否发送过绑定Service的请求,从前面的代码得知是没有发送过,因此,!
i.requested为true。
从前面的代码得知rebind值为false,那么(!
i.requested||rebind)的值为true。
如果IntentBindRecord中的应用程序进程记录大于0,则会调用注释2的代码,r.app.thread的类型为IApplicationThread,它的实现我们已经很熟悉了,是ActivityThread的内部类ApplicationThread,scheduleBindService方法如下所示。
frameworks/base/core/java/android/app/ActivityThread.java
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的信息封装成BindServiceData对象,需要注意的BindServiceData的成员变量rebind的值为false,后面会用到它。
接着将BindServiceData传入到sendMessage方法中。
sendMessage向H发送消息,我们接着查看H的handleMessage方法。
frameworks/base/core/java/android/app/ActivityThread.java
publicvoidhandleMessage(Messagemsg){
if(DEBUG_MESSAGES)Slog.v(TAG,">>>handling:
"+codeToString(g.what));
switch(msg.what){
...
caseBIND_SERVICE:
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"serviceBind");
handleBindService((BindServiceData)msg.obj);
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
break;
...
}
...
}
...
}
H在接收到BIND_SERVICE类型消息时,会在handleMessage方法中会调用handleBindService方法:
frameworks/base/core/java/android/app/ActivityThread.java
privatevoidhandleBindService(BindServiceDatadata){
Services=mServices.get(data.token);//1
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){//2
IBinderbinder=s.onBind(data.intent);//3
ActivityManagerNative.getDefault().publishService(
data.token,data.intent,binder);//4
}else{
s.onRebind(data.intent);//5
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token,SERVICE_DONE_EXECUTING_ANON,0,0);
}
ensureJitEnabled();
}
...
}
...
}
}
注释1处获取要绑定的Service。
注释2处的BindServiceData的成员变量rebind的值为false,这样会调用注释3处的代码来调用Service的onBind方法,这样Service处于绑定状态了。
如果rebind的值为true就会调用注释5处的Service的onRebind方法,结合前文的bindServiceLocked方法的注释4处,我们得知如果当前应用程序进程的Client端第一次与Service进行绑定,并且Service已经调用过onUnBind方法,则会调用Service的onRebind方法。
接着查看注释4的代码,实际上是调用AMS的publishService方法。
讲到这,先给出这一部分的代码时序图(不包括Service启动过程)
我们接着来查看AMS的publishService方法,代码如下所示。
frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java
publicvoidpublishService(IBindertoken,Intentintent,IBinderservice){
...
synchronized(this){
if(!
(tokeninstanceofServiceRecord)){
thrownewIllegalArgumentException("Invalidservicetoken");
}
mServices.publishServiceLocked((ServiceRecord)token,intent,service);
}
}
publishService方法中,调用了ActiveServices类型的mServices对象的publishServiceLocked方法:
frameworks/base/services/core/java/com/android/server/am/ActiveServices.java
voidpublishServiceLocked(ServiceRecordr,Intentintent,IBinderservice){
finallongorigId=Binder.clearCallingIdentity();
try{
...
for(intconni=r.connections.size()-1;conni>=0;conni--){
ArrayListclist=r.connections.valueAt(conni);
for(inti=0;i...
try{
c.conn.connected(r.name,service);//1
}catch(Exceptione){
...
}
}
}
}
serviceDoneExecutingLocked(r,mDestroyingServices.contains(r),false);
}
}finally{
Binder.restoreCallingIdentity(origId);
}
}
注释1处的代码,我在前面介绍过,c.conn指的是IServiceConnection,它的具体实现为ServiceDispatcher.InnerConnection,其中ServiceDispatcher是LoadedApk的内部类,ServiceDispatcher.InnerConnectiond的connected方法的代码如下所示。
frameworks/base/core/java/android/app/LoadedApk.java
staticfinalclassServiceDispatcher{
...
privatestaticclassInnerConnectionextendsIServiceConnection.Stub{
finalWeakReferencemDispatcher;
InnerConnection(LoadedApk.ServiceDispatchersd){
mDatcher=newWeakReference(sd);
}
publicvoidconnected(ComponentNamename,IBinderservice)throwsRemoteException{
LoadedApk.ServiceDispatchersd=mDispatcher.get();
if(sd!
=null){
sd.connected(name,service);//1
}
}
}
...
}
在注释1处调用了ServiceDispatcher类型的sd对象的connected方法,代码如下所示。
frameworks/base/core/java/android/app/LoadedApk.java
publicvoidconnected(ComponentNamename,IBinderservice){
if(mActivityThread!
=null){
mActivityThread.post(newRunConnection(name,service,0));//1
}else{
doConnected(name,service);
}
}
注释1处调用Handler类型的对象mActivityThread的post方法,mActivityThread实际上指向的是H。
因此,通过调用H的post方法将RunConnection对象的内容运行在主线程中。
RunConnection的定义如下所示。
frameworks/base/core/java/android/app/LoadedApk.java
privatefinalclassRunConnectionimplementsRunnable{
RunConnection(ComponentNamename,IBinderservice