配色: 字号:
Android Service的启动过程
2016-10-19 | 阅:  转:  |  分享 
  
AndroidService的启动过程

刚开始学习Service的时候以为它是一个线程的封装,也可以执行耗时操作。其实不然,Service是运行在主线程的。直接执行耗时操作是会阻塞主线程的。长时间就直接ANR了。



我们知道Service可以执行一些后台任务,是后台任务不是耗时的任务,后台和耗时是有区别的喔。

这样就很容易想到音乐播放器,天气预报这些应用是要用到Service的。当然如果要在Service中执行耗时操作的话,开个线程就可以了。



关于Service的运行状态有两种,启动状态和绑定状态,两种状态可以一起。

启动一个Service只需调用Context的startService方法,传进一个Intent即可。看起来好像很简单的说,那是因为Android为了方便开发者,做了很大程度的封装。那么你真的有去学习过Service是怎么启动的吗?Service的onCreate方法回调前都做了哪些准备工作?



先上一张图大致了解下,灰色背景框起来的是同一个类中的方法,如下图:



那接下来就从源码的角度来分析Service的启动过程。



当然是从Context的startService方法开始,Context的实现类是ContextImpl,那么我们就看到ContextImpl的startService方法即可,如下:



@Override

publicComponentNamestartService(Intentservice){

warnIfCallingFromSystemProcess();

returnstartServiceCommon(service,mUser);

}



会转到startServiceCommon方法,那跟进startServiceCommon方法方法瞧瞧。



privateComponentNamestartServiceCommon(Intentservice,UserHandleuser){

try{

validateServiceIntent(service);

service.prepareToLeaveProcess();

ComponentNamecn=ActivityManagerNative.getDefault().startService(

mMainThread.getApplicationThread(),service,service.resolveTypeIfNeeded(

getContentResolver()),getOpPackageName(),user.getIdentifier());



//代码省略



returncn;

}catch(RemoteExceptione){

thrownewRuntimeException("Failurefromsystem",e);

}

}



可以看到调用了ActivityManagerNative.getDefault()的startService方法来启动Service,ActivityManagerNative.getDefault()是ActivityManagerService,简称AMS。



那么现在启动Service的过程就转移到了ActivityManagerService,我们关注ActivityManagerService的startService方法即可,如下:



@Override

publicComponentNamestartService(IApplicationThreadcaller,Intentservice,

StringresolvedType,StringcallingPackage,intuserId)

throwsTransactionTooLargeException{



//代码省略



synchronized(this){

finalintcallingPid=Binder.getCallingPid();

finalintcallingUid=Binder.getCallingUid();

finallongorigId=Binder.clearCallingIdentity();

ComponentNameres=mServices.startServiceLocked(caller,service,

resolvedType,callingPid,callingUid,callingPackage,userId);

Binder.restoreCallingIdentity(origId);

returnres;

}

}



在上述的代码中,调用了ActiveServices的startServiceLocked方法,那么现在Service的启动过程从AMS转移到了ActiveServices了。



继续跟进ActiveServices的startServiceLocked方法,如下:



ComponentNamestartServiceLocked(IApplicationThreadcaller,Intentservice,StringresolvedType,

intcallingPid,intcallingUid,StringcallingPackage,intuserId)

throwsTransactionTooLargeException{



//代码省略



ServiceLookupResultres=

retrieveServiceLocked(service,resolvedType,callingPackage,

callingPid,callingUid,userId,true,callerFg);



//代码省略





ServiceRecordr=res.record;



//代码省略



returnstartServiceInnerLocked(smap,service,r,callerFg,addToStarting);

}



在startServiceLocked方法中又会调用startServiceInnerLocked方法,



我们瞧瞧startServiceInnerLocked方法,



ComponentNamestartServiceInnerLocked(ServiceMapsmap,Intentservice,ServiceRecordr,

booleancallerFg,booleanaddToStarting)throwsTransactionTooLargeException{

ProcessStats.ServiceStatestracker=r.getTracker();

if(stracker!=null){

stracker.setStarted(true,mAm.mProcessStats.getMemFactorLocked(),r.lastActivity);

}

r.callStart=false;

synchronized(r.stats.getBatteryStats()){

r.stats.startRunningLocked();

}

Stringerror=bringUpServiceLocked(r,service.getFlags(),callerFg,false);



//代码省略



returnr.name;

}



startServiceInnerLocked方法内部调用了bringUpServiceLocked方法,此时启动过程已经快要离开ActiveServices了。继续看到bringUpServiceLocked方法。如下:



privatefinalStringbringUpServiceLocked(ServiceRecordr,intintentFlags,booleanexecInFg,

booleanwhileRestarting)throwsTransactionTooLargeException{



//代码省略



if(app!=null&&app.thread!=null){

try{

app.addPackage(r.appInfo.packageName,r.appInfo.versionCode,mAm.mProcessStats);

realStartServiceLocked(r,app,execInFg);

returnnull;

}



//代码省略



returnnull;

}



省略了大部分if判断,相信眼尖的你一定发现了核心的方法,那就是

realStartServiceLocked,没错,看名字就像是真正启动Service。那么事不宜迟跟进去探探吧。如下:



privatefinalvoidrealStartServiceLocked(ServiceRecordr,

ProcessRecordapp,booleanexecInFg)throwsRemoteException{



//代码省略



booleancreated=false;

try{



//代码省略

app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);

app.thread.scheduleCreateService(r,r.serviceInfo,

mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),

app.repProcState);

r.postNotification();

created=true;

}catch(DeadObjectExceptione){

Slog.w(TAG,"Applicationdeadwhencreatingservice"+r);

mAm.appDiedLocked(app);

throwe;

}



//代码省略



sendServiceArgsLocked(r,execInFg,true);



//代码省略



}



找到了。app.thread调用了scheduleCreateService来启动Service,而app.thread是一个ApplicationThread,也是ActivityThread的内部类。此时已经到了主线程。

那么我们探探ApplicationThread的scheduleCreateService方法。如下:



publicfinalvoidscheduleCreateService(IBindertoken,

ServiceInfoinfo,CompatibilityInfocompatInfo,intprocessState){

updateProcessState(processState,false);

CreateServiceDatas=newCreateServiceData();

s.token=token;

s.info=info;

s.compatInfo=compatInfo;



sendMessage(H.CREATE_SERVICE,s);

}



对待启动的Service组件信息进行包装,然后发送了一个消息。我们关注这个CREATE_SERVICE消息即可。



publicvoidhandleMessage(Messagemsg){



//代码省略



caseCREATE_SERVICE:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"serviceCreate");

handleCreateService((CreateServiceData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;



//代码省略



}



在handleMessage方法中接收到这个消息,然后调用了handleCreateService方法,跟进handleCreateService探探究竟:



privatevoidhandleCreateService(CreateServiceDatadata){

//Ifwearegettingreadytogcaftergoingtothebackground,well

//wearebackactivesoskipit.

unscheduleGcIdler();



LoadedApkpackageInfo=getPackageInfoNoCheck(

data.info.applicationInfo,data.compatInfo);

Serviceservice=null;

try{

java.lang.ClassLoadercl=packageInfo.getClassLoader();

service=(Service)cl.loadClass(data.info.name).newInstance();

}catch(Exceptione){

if(!mInstrumentation.onException(service,e)){

thrownewRuntimeException(

"Unabletoinstantiateservice"+data.info.name

+":"+e.toString(),e);

}

}



try{

if(localLOGV)Slog.v(TAG,"Creatingservice"+data.info.name);



ContextImplcontext=ContextImpl.createAppContext(this,packageInfo);

context.setOuterContext(service);



Applicationapp=packageInfo.makeApplication(false,mInstrumentation);

service.attach(context,this,data.info.name,data.token,app,

ActivityManagerNative.getDefault());

service.onCreate();

mServices.put(data.token,service);

try{

ActivityManagerNative.getDefault().serviceDoneExecuting(

data.token,SERVICE_DONE_EXECUTING_ANON,0,0);

}catch(RemoteExceptione){

//nothingtodo.

}

}catch(Exceptione){

if(!mInstrumentation.onException(service,e)){

thrownewRuntimeException(

"Unabletocreateservice"+data.info.name

+":"+e.toString(),e);

}

}

}



终于击破,这个方法很核心的。一点点分析



首先获取到一个LoadedApk对象,在通过这个LoadedApk对象获取到一个类加载器,通过这个类加载器来创建Service。如下:



java.lang.ClassLoadercl=packageInfo.getClassLoader();

service=(Service)cl.loadClass(data.info.name).newInstance();



接着调用ContextImpl的createAppContext方法创建了一个ContextImpl对象。



之后再调用LoadedApk的makeApplication方法来创建Application,这个创建过程如下:



publicApplicationmakeApplication(booleanforceDefaultAppClass,

Instrumentationinstrumentation){

if(mApplication!=null){

returnmApplication;

}



Applicationapp=null;



StringappClass=mApplicationInfo.className;

if(forceDefaultAppClass||(appClass==null)){

appClass="android.app.Application";

}



try{

java.lang.ClassLoadercl=getClassLoader();

if(!mPackageName.equals("android")){

initializeJavaContextClassLoader();

}

ContextImplappContext=ContextImpl.createAppContext(mActivityThread,this);

app=mActivityThread.mInstrumentation.newApplication(

cl,appClass,appContext);

appContext.setOuterContext(app);

}catch(Exceptione){

if(!mActivityThread.mInstrumentation.onException(app,e)){

thrownewRuntimeException(

"Unabletoinstantiateapplication"+appClass

+":"+e.toString(),e);

}

}

mActivityThread.mAllApplications.add(app);

mApplication=app;



if(instrumentation!=null){

try{

instrumentation.callApplicationOnCreate(app);

}catch(Exwww.shanxiwang.netceptione){

if(!instrumentation.onException(app,e)){

thrownewRuntimeException(

"Unabletocreateapplication"+app.getClass().getName()

+":"+e.toString(),e);

}

}

}



//RewritetheR''constants''foralllibraryapks.

SparseArraypackageIdentifiers=getAssets(mActivityThread)

.getAssignedPackageIdentifiers();

finalintN=packageIdentifiers.size();

for(inti=0;i
finalintid=packageIdentifiers.keyAt(i);

if(id==0x01||id==0x7f){

continue;

}



rewriteRValues(getClassLoader(),packageIdentifiers.valueAt(i),id);

}



returnapp;

}



当然Application是只有一个的,从上述代码中也可以看出。



在回来继续看handleCreateService方法,之后service调用了attach方法关联了ContextImpl和Application等



最后service回调了onCreate方法,



service.onCreate();

mServices.put(data.token,service);



并将这个service添加进了一个了列表进行管理。



至此service启动了起来,以上就是service的启动过程。



你可能还想要知道onStartCommand方法是怎么被回调的?可能细心的你发现了在ActiveServices的realStartServiceLocked方法中,那里还有一个sendServiceArgsLocked方法。是的,那个就是入口。



那么我们跟进sendServiceArgsLocked方法看看onStartCommand方法是怎么回调的。



privatefinalvoidsendServiceArgsLocked(ServiceRecordr,booleanexecInFg,

booleanoomAdjusted)throwsTransactionTooLargeException{

finalintN=r.pendingStarts.size();



//代码省略



try{



//代码省略



r.app.thread.scheduleServiceArgs(r,si.taskRemoved,si.id,flags,si.intent);

}catch(TransactionTooLargeExceptione){

if(DEBUG_SERVICE)Slog.v(TAG_SERVICE,"Transactiontoolarge:intent="

+si.intent);

caughtException=e;

}catch(RemoteExceptione){

//Remoteprocessgone...we''llletthenormalcleanuptakecareofthis.

if(DEBUG_SERVICE)Slog.v(TAG_SERVICE,"Crashedwhilesendingargs:"+r);

caughtException=e;

}



//代码省略

}



可以看到onStartCommand方法回调过程和onCreate方法的是很相似的,都会转到app.thread。那么现在就跟进ApplicationThread的scheduleServiceArgs。

你也可能猜到了应该又是封装一些Service的信息,然后发送一个消息,handleMessage接收。是的,源码如下:



publicfinalvoidscheduleServiceArgs(IBindertoken,booleantaskRemoved,intstartId,

intflags,Intentargs){

ServiceArgsDatas=newServiceArgsData();

s.token=token;

s.taskRemoved=taskRemoved;

s.startId=startId;

s.flags=flags;

s.args=args;



sendMessage(H.SERVICE_ARGS,s);

}



publicvoidhandleMessage(Messagemsg){



//代码省略



caseSERVICE_ARGS:

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"serviceStart");

handleServiceArgs((ServiceArgsData)msg.obj);

Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);

break;



//代码省略

}



咦,真的是这样。谜底应该就在handleServiceArgs方法了,那么赶紧瞧瞧,源码如下:



privatevoidhandleServiceArgs(ServiceArgsDatadata){

Services=mServices.get(data.token);

if(s!=null){

try{

if(data.args!=null){

data.args.setExtrasClassLoader(s.getClassLoader());

data.args.prepareToEnterProcess();

}

intres;

if(!data.taskRemoved){

res=s.onStartCommand(data.args,data.flags,data.startId);

}else{

s.onTaskRemoved(data.args);

res=Service.START_TASK_REMOVED_COMPLETE;

}



QueuedWork.waitToFinish();



try{

ActivityManagerNative.getDefault().serviceDoneExecuting(

data.token,SERVICE_DONE_EXECUTING_START,data.startId,res);

}catch(RemoteExceptione){

//nothingtodo.

}

ensureJitEnabled();

}catch(Exceptione){

if(!mInstrumentation.onException(s,e)){

thrownewRuntimeException(

"Unabletostartservice"+s

+"with"+data.args+":"+e.toString(),e);

}

}

}

}



可以看到回调了onStartCommand方法。



以上就是Service的启动过程的源码分析。



从中,我理解了Service的启动过程的同时,阅读源码的能力也提高了,分析源码的时候我没能力把每一个变量,每一个方法都搞懂,我关注的都是一些关键的字眼,比如这篇文章就是start呀,service呀。会有那种感觉,就是这里没错了。当然如果陷入胡同了也要兜出来。



这样的分析也能够摸清整体的过程,对于细节,等我有扎实的功底了在去研究吧。

献花(0)
+1
(本文系网络学习天...首藏)