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呀。会有那种感觉,就是这里没错了。当然如果陷入胡同了也要兜出来。
这样的分析也能够摸清整体的过程,对于细节,等我有扎实的功底了在去研究吧。
|
|